diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f916713ee973039803a9274da2979245f97913fe
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.env
+__pycache__/
+*.pyc
+*.pyo
+modules\firebase_credentials.json
+test*
\ No newline at end of file
diff --git a/.vscode/.ai-schema-ignore b/.vscode/.ai-schema-ignore
new file mode 100644
index 0000000000000000000000000000000000000000..0226a84e2259a61c00526f28d7a2c9423c86d325
--- /dev/null
+++ b/.vscode/.ai-schema-ignore
@@ -0,0 +1,261 @@
+# ============================================================
+# .ai-schema-ignore template file
+# Defines files and folders to exclude from schema generation
+# ============================================================
+
+# -----------------------------
+# Universal File Extensions
+# -----------------------------
+*.diff
+*.err
+*.orig
+*.log
+*.rej
+*.swo
+*.swp
+*.vi
+*~
+*.tmp
+*.temp
+*.bak
+*.backup
+*.old
+*.lock
+*.pid
+*.cache
+*.zip
+*.rar
+*.7z
+*.tar
+*.tar.gz
+*.tgz
+*.gz
+*.bz2
+*.xz
+*.iso
+*.img
+*.vsix
+*.code-workspace
+*.ai-schema-ignore
+*.bundle.js
+*.bundle.js.map
+*.gps-extension/
+
+# -----------------------------
+# Image & Media Files
+# -----------------------------
+*.png
+*.jpg
+*.jpeg
+*.webp
+*.ico
+*.svg
+*.gif
+*.psd
+*.tiff
+*.bmp
+*.mp3
+*.wav
+*.ogg
+*.flac
+*.mp4
+*.avi
+*.mov
+*.wmv
+*.mkv
+*.webm
+
+# -----------------------------
+# Font Files
+# -----------------------------
+*.ttf
+*.otf
+*.woff
+*.woff2
+*.eot
+
+# -----------------------------
+# Specific Files
+# -----------------------------
+LICENSE
+LICENSE.txt
+CHANGELOG.md
+README.md
+README.txt
+project_scheme.ps1
+project_structure_and_code.txt
+project_structure.txt
+scheme_creator.py
+project_analysis.txt
+.gitignore
+package-lock.json
+sftp.json
+
+# -----------------------------
+# General Development Folders
+# -----------------------------
+.DS_Store
+Thumbs.db
+.cache/
+.project
+.settings/
+.tmproj
+*.esproj
+nbproject/
+*.sublime-project
+*.sublime-workspace
+.vscode-test/
+coverage/
+reports/
+logs/
+.ai-schema/
+
+# Dreamweaver
+_notes/
+dwsync.xml
+
+# Komodo
+*.komodoproject
+.komododotools/
+
+# Source Control
+.hg/
+.svn/
+.CVS/
+.git/
+
+# Development Artefacts
+intermediate/
+.idea/
+cache/
+.vcode/
+node_modules/
+libs/
+.tools/
+languages/
+dist/
+build/
+out/
+
+# -----------------------------
+# WordPress Specific
+# -----------------------------
+wp-config.php
+wp-config-sample.php
+debug.log
+.htaccess
+*.db
+*.sql
+*.sqlite
+*.csv
+*.env
+wp-admin/
+wp-includes/
+uploads/
+cache/
+wpcache/
+upgrade/
+*.mo
+*.po
+*.pot
+*.min.js
+*.min.css
+vendor/
+
+# WooCommerce
+woocommerce/logs/
+woocommerce/tmp/
+woocommerce/packages/
+woocommerce-plugin-backups/
+woocommerce-logs/
+
+# Plugins
+*.zip
+build/
+assets/
+languages/
+phpunit.xml
+phpunit.xml.dist
+tests/
+tests/_output/
+tests/_support/
+tests/_data/
+
+# -----------------------------
+# Language-Specific Ignores
+# -----------------------------
+# Node.js / TypeScript
+node_modules/
+dist/
+build/
+*.tsbuildinfo
+
+# Python
+__pycache__/
+*.pyc
+*.pyo
+*.pyd
+*.egg
+*.egg-info
+*.manifest
+*.spec
+pip-wheel-metadata/
+
+# Java
+*.class
+*.jar
+*.war
+*.ear
+*.jmod
+target/
+out/
+
+# .NET
+bin/
+obj/
+*.dll
+*.pdb
+*.exe
+
+# Ruby
+*.gem
+*.rbc
+.bundle/
+vendor/
+
+# PHP
+vendor/
+*.phar
+
+# C / C++
+*.o
+*.out
+*.so
+*.dylib
+*.a
+
+# Go
+*.exe
+*.test
+vendor/
+go.sum
+
+# Rust
+target/
+Cargo.lock
+
+# Swift / iOS
+*.xcworkspace/
+*.xcuserdata/
+DerivedData/
+Pods/
+
+# Android
+*.apk
+*.ap_
+*.dex
+*.gradle
+.gradle/
+local.properties
+
+myenv/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..6881b100d9447ec92944604d3b75b9241fc4f6e9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,25 @@
+# استخدم صورة أساسية خفيفة من Python
+# force rebuild
+FROM python:3.11
+
+# اضبط مجلد العمل داخل الحاوية
+WORKDIR /app
+
+# انسخ ملف requirements لو عندك
+COPY requirements.txt .
+
+# نزّل المتطلبات
+RUN pip install --no-cache-dir -r requirements.txt
+
+# انسخ ملفات المشروع
+COPY . /app
+
+# عرّف البورت اللي البرنامج هيشتغل عليه
+EXPOSE 7860
+
+# استخدم Gunicorn بدلاً من uvicorn مباشرة لدعم عدة مستخدمين (Workers)
+# رقم 4 يعني أنه سيشغل 4 عمليات (Processes) لخدمة الطلبات في نفس الوقت
+# # CMD ["gunicorn", "app:app", "--workers", "4", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:7860", "--timeout", "120"]
+# CMD ["gunicorn", "app:app","--workers", "2","--worker-class", "uvicorn.workers.UvicornWorker","--bind", "0.0.0.0:7860","--timeout", "180"]
+# لو بتستخدم FastAPI (مع uvicorn):
+CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 6eb4bfbd044027f3af0733404626d2de0f8b7f5e..b42366248eabfd0e6578d83e0b60e14ec029ff01 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
---
-title: ContiAI
-emoji: 🌍
-colorFrom: yellow
-colorTo: red
+title: ContiAI-v4
+emoji: 🐨
+colorFrom: blue
+colorTo: green
sdk: docker
pinned: false
+license: apache-2.0
+app_port: 7860
---
-
-Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
diff --git a/agents/analysis_phase/Introduction.py b/agents/analysis_phase/Introduction.py
new file mode 100644
index 0000000000000000000000000000000000000000..dec1a5497554718659ca2c383a84784edec8137c
--- /dev/null
+++ b/agents/analysis_phase/Introduction.py
@@ -0,0 +1,114 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm_g
+from schemas import IntroductionOutput
+
+def intro_agent():
+ model=llm_g()
+ return Agent(
+ role="Human-Crafted Arabic Introduction Writer",
+ goal=(
+ "Create a deeply human, stylistically rich, emotionally resonant Arabic introduction "
+ "for a training program based on the provided topic ({topic}), outlines, units, and outcomes. "
+ "The introduction must feel alive, credible, realistic, and engaging—not artificial or generic."
+ ),
+ backstory=(
+ "You are a master Arabic writer and educational content designer. "
+ "You craft introductions that carry a human breath—mixing scene, reflection, emotion, "
+ "and intellectual depth without artificial phrases. "
+ "Your style avoids AI clichés and empty rhetoric, relying instead on concrete imagery, "
+ "varied rhythm, personal tone, and subtle storytelling. "
+ "You write for {audience} with professionalism, depth, and authenticity."
+ ),
+ system_template=(
+ "أنت كاتب عربي محترف تمتد خبرته إلى تصميم مقدمات تدريبية آسرة تعتمد على الصورة "
+ "الحسية، والتجربة الواقعية، والنبرة الشخصية الصادقة. كتابتك تشبه النصوص البشرية القوية "
+ "وليست مصطنعة أو آلية.\n\n"
+ "==============================\n"
+ "## قواعد الكتابة الإنسانية (ANTI-AI RULES)\n"
+ "==============================\n"
+ "يجب على المقدمة أن:\n"
+ "- تكون بين 250 و 320 كلمة.\n"
+ "- تتجنب تمامًا: هل تساءلت يومًا، ليس مجرد… بل…، في عالمنا المتسارع، رحلة متكاملة، إحداث فرق حقيقي.\n"
+ "- تتجنب الأسلوب الإنشائي الدعائي واللغة البراقة الفارغة.\n"
+ "- تحتوي على جُمل قصيرة وأخرى طويلة (تنويع الإيقاع).\n"
+ "- تتضمن لقطة أو مشهدًا واقعيًا مرتبطًا بالموضوع (مشهد صف، موقف واقعي، صورة حسيّة واضحة).\n"
+ "- تحمل لمسة شخصية: دهشة، ملاحظة، موقف شعوري، رأي بسيط.\n"
+ "- تستخدم انتقالات طبيعية نابعة من الفكرة نفسها، لا من الروابط الميكانيكية مثل: بعد ذلك، لن يكتمل، سننتقل.\n"
+ "- تستخدم لغة عربية قوية وواضحة، بلا مبالغة، بلا زخرفة، بلا تكرار.\n"
+ "- تعرض مشكلة حقيقية أو تحديًا واقعيًا يتعلق بالموضوع.\n"
+ "- تبتعد عن العموميات والعبارات المستهلكة.\n\n"
+ "==============================\n"
+ "## أساليب افتتاح مسموح بها\n"
+ "==============================\n"
+ "يمكنك البدء بـ:\n"
+ "- مشهد قصير واقعي.\n"
+ "- سطر من تجربة إنسانية.\n"
+ "- تساؤل تأملي صادق (غير إنشائي).\n"
+ "- حقيقة أو رقم لها علاقة مباشرة بالموضوع.\n"
+ "- حكمة أو قول مناسب لكن غير مستهلك.\n\n"
+ "==============================\n"
+ "## البنية المرنة للمقدمة\n"
+ "==============================\n"
+ "1. افتتاح مشهدي أو واقعي أو تأملي.\n"
+ "2. ربط المشهد بطبيعة موضوع التدريب.\n"
+ "3. عرض المشكلة أو التحدي الحقيقي الذي يعالجه البرنامج.\n"
+ "4. توضيح قيمة الموضوع والفائدة بأسلوب ملموس لا إنشائي.\n"
+ "5. وعد تعليمي مشتق من المخرجات لكن بلغة إنسانية طبيعية.\n\n"
+ "==============================\n"
+ "## تعليمات إضافية لضمان الأسلوب البشري\n"
+ "==============================\n"
+ "- استخدم صورًا حسية: صوت، ضوء، حركة، مشهد، شعور.\n"
+ "- لا تجعل الجمل كلها بنفس الإيقاع أو الطول.\n"
+ "- لا تبدأ بأسئلة رنانة بلا معنى.\n"
+ "- تجنب الترتيب النمطي للجمل الذي ينتجه الذكاء الاصطناعي.\n"
+ "- قدم فائدة أو ملاحظة شخصية حقيقية.\n"
+ "- اربط الكلمات بالموقف وليس بالقوالب.\n\n"
+ ),
+ llm=model,
+ memory=False,
+ allow_delegation=False,
+ verbose=True,
+ max_iter=50,
+ cache=False,
+)
+
+def intro_task(intro_agent):
+ return Task(
+ description=(
+ "Write a human-like Arabic introduction (300–400 words) that reflects true human rhythm, "
+ "## INPUT\n"
+ "You have access to the program’s full context:\n"
+ "- Topic: {topic}\n"
+ "- Outline (units and subtopics): {outlines}\n"
+ "- Unit details: {units}\n"
+ "- Learning outcomes: {outcomes}\n\n"
+ "## OBJECTIVE\n"
+ "Write an Arabic introduction that connects the learner emotionally and intellectually to the training content. "
+ "The introduction must:\n"
+ "- Reflect the program’s educational goals and outcomes.\n"
+ "- Be motivational, concise, and linguistically natural for {audience}.\n"
+ "## MUST INCLUDE:\n"
+ "• نبرة شخصية.\n"
+ "• لغة خالية من الإنشاء المكرر والعبارات المستهلكة.\n"
+ "• تنويع طول الجمل.\n"
+ "• انتقالات طبيعية.\n\n"
+ "## MUST AVOID:\n"
+ "• الأسئلة الافتتاحية المعلبة.\n"
+ "• الإنشاء الفارغ.\n"
+ "• الإفراط في الجمل الطويلة.\n"
+ "• العبارات التسويقية.\n"
+ "• الكلمات اللامعة الخاوية.\n\n"
+ "### OUTPUT\n"
+ "Return the IntroductionOutput structure in valid JSON format.\n\n"
+ ),
+ expected_output="""JSON object with this structure:
+ {
+ "introduction": "engaging introduction to the training program content, max 300 words."
+ }
+ """,
+ output_json=IntroductionOutput,
+ agent=intro_agent,
+ human_input=False,
+)
diff --git a/agents/analysis_phase/__init__.py b/agents/analysis_phase/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe00669c5f890f6e6c8e723cc9a93e2753da9955
--- /dev/null
+++ b/agents/analysis_phase/__init__.py
@@ -0,0 +1,10 @@
+from .analysis_report import report_agent, report_task
+from .analysis import analysis_agent, analysis_task
+from .objectives import (
+ objectives_generator,
+ objectives_task,
+ get_bloom_verb,
+)
+from .outcomes import outcomes_generator, outcomes_task
+from .outliner import outline_agent, outline_task
+from .Introduction import intro_agent, intro_task
diff --git a/agents/analysis_phase/analysis.py b/agents/analysis_phase/analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..d09d1bef2383f4871d179e16dcdbc40a22bb88a2
--- /dev/null
+++ b/agents/analysis_phase/analysis.py
@@ -0,0 +1,103 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+from schemas import AnalysisOutput
+
+def analysis_agent():
+ model=llm()
+ return Agent(
+ role="Training Analysis Agent",
+ goal="\n".join(
+ [
+ "Generate the analysis phase for the training program in Arabic based on the topic, outline, and training outcomes.",
+ "Follow the DNA methodology defined in the Outline Agent.",
+ "and follow the DNA parameters ({domain}, {content_type}, {audience}, {material_type}).",
+ "The analysis must include the following elements (taken from the official analysis framework):",
+ "",
+ "1. Goal:",
+ "- Overall goal expected after the training program.",
+ "- Must start with: 'أن يتمكّن المتدرب من ...'.",
+ "- Should be a complete sentence covering all training topics.",
+ "- Must be comprehensive, not limited to one aspect.",
+ "",
+ "2. Target Audience:",
+ "- The group receiving the training.",
+ "- Include average age (e.g., شباب في العشرينات، موظفون في الثلاثينات).",
+ "",
+ "3. Previous Experiences:",
+ "- Short sentences written as noun-phrases (مصادر).",
+ "- Express prior practical or knowledge-based experiences.",
+ "- Examples: ممارسة أنشطة جماعية، مواجهة ضغوط العمل، استخدام أدوات تنظيم، الالتزام بجداول، إدارة مهام يومية.",
+ "",
+ "4. Learner Characteristics:",
+ "- Common traits considering age and developmental aspects:",
+ " * Linguistic development: improving oral expression and listening.",
+ " * Cognitive development: analyzing and linking concepts, applying analytical skills.",
+ " * Social development: tendency to interact and collaborate.",
+ " * Emotional development: reacting to emotional situations.",
+ " * Personality growth: building independent identity and attitudes.",
+ " * Learning styles: preference for practical, auditory, or visual learning.",
+ "",
+ "5. Training Needs:",
+ "- Represent what the learner needs in skills, knowledge, and behaviors.",
+ "- Must be extracted from the training topics.",
+ "- 6 sentences required, each a noun-phrase.",
+ "- Each starts with a مصدر (e.g., فهم، إدراك، توظيف، استيعاب).",
+ "- Must not be copied titles but rephrased needs.",
+ "",
+ "6. Constraints:",
+ "- Barriers that may negatively affect training.",
+ "- Two types:",
+ " * Trainer constraints (4 sentences):Examples: (e.g.,ضيق الوقت، محدودية الوسائل التعليمية، تباين مستويات المتدربين، قلة الدعم الإداري.).",
+ " * Trainee constraints (4 sentences): Examples:(e.g.,ضعف الالتزام، ضعف الحافز، انشغالات شخصية، قلة الخبرة التقنية.).",
+ "- All sentences must start with a مصدر (محدودية، ضعف، صعوبة، تباين).",
+ "- Written as complete noun-phrases only.",
+ "",
+ "7. Duration:",
+ "- Exact training duration (hours/days).",
+ "- Training day = 4 hours.",
+ "- Examples: دورة يوم واحد = 4 ساعات، دورتان = 8 ساعات.",
+ "",
+ "8. Sources of Analysis:",
+ "- Pre-training instructional design processes.",
+ "- Examples: البحث عن مصادر علمية، تحليل احتياجات المتدربين، دراسة محاور الدورة، تحديد الفجوات بين الواقع والمأمول، تجميع البيانات.",
+ "- Must be written as noun-phrases starting and ending with a مصدر (e.g., جمع البيانات وتحليلها).",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "This agent acts as an instructional designer responsible for producing the full analysis phase.",
+ "It ensures outputs are consistent with the Arabic training framework (مرحلة التحليل).",
+ "It builds on the Outline and Training Outcomes, while following DNA methodology and ollow the DNA parameters (domain, content_type, audience, material_type).",
+ ]
+ ),
+ llm=model,
+ verbose=True,
+)
+
+
+# ====== Task ======
+def analysis_task(analysis_agent):
+ return Task(
+ description="\n".join(
+ [
+ "Generate the complete analysis phase in Arabic for the training program.",
+ "Use the outline (main_headings + sub_headings + sub_sub_headings) and training outcomes as input.",
+ "Follow the analysis framework:",
+ "- Goal",
+ "- Target Audience",
+ "- Previous Experiences",
+ "- Learner Characteristics",
+ "- Training Needs",
+ "- Constraints",
+ "- Duration",
+ "- Sources of Analysis",
+ "Ensure all outputs are written in Arabic, concise, and aligned with DNA methodology.",
+ "Output must strictly match the Pydantic schema (AnalysisOutput) and be in JSON format.",
+ ]
+ ),
+ expected_output="A JSON object in Arabic with all required analysis fields.",
+ output_json=AnalysisOutput,
+ agent=analysis_agent,
+)
diff --git a/agents/analysis_phase/analysis_report.py b/agents/analysis_phase/analysis_report.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c7b32c788725d7e474eb5f84b40859a48c44202
--- /dev/null
+++ b/agents/analysis_phase/analysis_report.py
@@ -0,0 +1,66 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+
+
+# ====== Agent ======
+def report_agent():
+ model=llm()
+ return Agent(
+ role="Training Report Builder",
+ goal="\n".join(
+ [
+ "Take the outputs from title_agent, outline_agent, training_agent, and analysis_agent.",
+ "Generate a well-structured HTML report in Arabic.",
+ "",
+ "Rules:",
+ "- At the very top of the page, display the title from title_agent output as a main heading (
).",
+ "- The training_agent introduction should appear under a section titled: 'المقدمة'.",
+ "- The outline_agent output should appear under a section titled: 'محتويات الحقيبة'.",
+ "- The training_agent learning outcomes should appear under a section titled: 'مخرجات البرنامج التدريبي'.",
+ "- The analysis_agent output should appear under a section titled: 'مرحلة التحليل'.",
+ "",
+ "For the 'مرحلة التحليل' section:",
+ "- Present it inside an HTML table.",
+ "- The table should have two columns: 'العنصر' and 'الوصف'.",
+ "- Each row corresponds to one analysis element (الهدف، الفئة المستهدفة، الخبرات السابقة، خصائص المتدربين، الاحتياجات التدريبية، القيود، المدة الزمنية، مصادر التحليل).",
+ "",
+ "The final HTML page should be clean and well-structured with Arabic titles and proper formatting.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "This agent acts as a report generator.",
+ "It combines all outputs (title, outline, training outcomes, analysis) into one structured HTML training portfolio.",
+ ]
+ ),
+ llm=model,
+ verbose=True,
+)
+
+
+# ====== Task ======
+def report_task(report_agent):
+ return Task(
+ description="\n".join(
+ [
+ "Build an HTML page combining all outputs:",
+ "- At the top of the page, show the title (from title_agent output) as .",
+ "- Section 1: 'المقدمة' → from training_agent output (introduction).",
+ "- Section 2: 'محتويات الحقيبة' → from outline_agent output.",
+ "- Section 3: 'مخرجات البرنامج التدريبي' → from training_agent output (learning outcomes as a bulleted list).",
+ "- Section 4: 'مرحلة التحليل' → from analysis_agent output.",
+ " - The analysis section must be presented inside an HTML table same as this template {html_template}.",
+ "use css style to enhance the design more and the table responsive.",
+ "Care about colors, headers, and fonts.",
+ "don't change the style of analysis table",
+ " - The table should have two columns: 'العنصر' and 'الوصف'.",
+ " - Each row corresponds to one analysis element (goal, target audience, previous experiences, learner characteristics, training needs, constraints, duration, sources of analysis).",
+ "",
+ "Ensure the HTML page is clean, well-structured, and properly formatted in Arabic.",
+ ]
+ ),
+ expected_output="A single HTML string with a title, three sections, and a table for the analysis section. and don't put the code in html``` ```",
+ agent=report_agent,
+)
diff --git a/agents/analysis_phase/objectives.py b/agents/analysis_phase/objectives.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa207c8fc820ab2dd26e7bc912a6d40b45f2ab70
--- /dev/null
+++ b/agents/analysis_phase/objectives.py
@@ -0,0 +1,290 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import bloom_taxonomy_2, objectives_dimensions, llm_g
+from schemas import LearningObjectivesOutput
+
+
+def get_bloom_verb(level: str) -> str:
+ """Returns verbs from the given Bloom's taxonomy level."""
+
+ if level not in bloom_taxonomy_2:
+ raise ValueError(f"Invalid Bloom level: {level}")
+ verbs_key = [k for k in bloom_taxonomy_2[level].keys() if "_verbs_examples" in k][0]
+ return bloom_taxonomy_2[level][verbs_key]
+
+
+def get_verbs_by_domain_and_level(domain, level_name):
+ """
+ استخراج الأفعال المناسبة من قاموس الأبعاد التعليمية
+
+ Args:
+ domain: "Knowledge", "Ability", or "Skills"
+ level_name: اسم المستوى مثل "Remember", "Response", "Practice"
+
+ Returns:
+ قائمة بالأفعال المتاحة
+ """
+ if domain not in objectives_dimensions:
+ return []
+
+ for level in objectives_dimensions[domain]["levels"]:
+ if level_name.lower() in level["level_name"].lower():
+ return level["verbs_examples"]
+
+ return []
+
+
+def objectives_generator():
+ model=llm_g()
+ return Agent(
+ role="Expert Learning Objectives Designer (Instructional Design Specialist)",
+ goal=(
+ "Design a comprehensive list of clear, measurable, and achievable learning objectives in Arabic "
+ "for each subtopic in the training curriculum. Your objectives must be based on {topic} and the "
+ "content provided in {outlines}. "
+ "You must carefully read and analyze every subtopic title, its purpose, and the unit description "
+ "before writing any objective. "
+ "Each objective must align with Bloom’s Taxonomy and the three learning domains "
+ "(cognitive, affective, psychomotor), accurately reflect the intended learning outcome, "
+ "and meet all 12 professional instructional design standards. "
+ "**Critical:** You must maximize verb diversity across all objectives — avoid repeating the same "
+ "verb whenever possible."
+ ),
+ # system_template="",
+ backstory=(
+ "You are an expert instructional designer with deep experience in creating professional training programs. "
+ "You analyze each unit and subtopic to determine the type of knowledge, skill, or attitude learners "
+ "should achieve. "
+ "Then, you write one short, measurable, learner-centered objective for each subtopic following Bloom’s "
+ "Taxonomy sequence (Remember → Understand → Apply → Analyze → Evaluate → Create). "
+ "**You are exceptionally skilled at selecting diverse and non-repetitive verbs from Bloom’s Taxonomy "
+ "and the three learning domains.** "
+ "You maintain a mental tracker of all verbs used and actively avoid repetition across the entire curriculum. "
+ "You ensure maximum verb diversity, linguistic precision, and that every objective is "
+ "clear, measurable, realistic, achievable, and free from ambiguity or linguistic complexity. "
+ "Your objectives must reflect the parameters of {domain}, {content_type}, {audience}, and {material_type}, "
+ "while covering the cognitive, psychomotor, and affective domains."
+ ),
+ llm=model,
+ verbose=True,
+ max_iter=100,
+)
+
+
+def objectives_task(objectives_agent):
+ return Task(
+ description=(
+ "You have a complete and well-structured training curriculum provided in outlines: {outlines} and units details: {units}. "
+ "Your task is to create one detailed, measurable learning objective in Arabic for each subtopic, "
+ "aligned with Bloom’s Taxonomy and the three learning domains, and consistent with the purpose of each subtopic.\n\n"
+ "### Step-by-Step Process\n"
+ "1. Read the curriculum overview to understand the full learning journey.\n"
+ "2. **Before you begin, review the complete list of Bloom’s action verbs and the three domains for each level to plan maximum diversity.**\n"
+ "3. **Create a mental or written record of verbs as you use them to avoid repetition.**\n"
+ "4. For each unit:\n"
+ " a. Analyze the unit description to understand the learning scope and intended outcomes.\n"
+ " b. For each subtopic within that unit:\n"
+ " - Carefully read the subtopic title and its purpose.\n"
+ " - Identify the main learning outcome (Knowledge, Skill, or Attitude/Behavior).\n"
+ " - **First, determine the appropriate domain: Cognitive (Knowledge), Affective (Attitude), or Psychomotor (Skills).**\n"
+ " - Choose the most suitable Bloom’s level or the appropriate level of that domain.\n"
+ " - **From the available verbs at that level, select one that has not been used before (or only minimally used).**\n"
+ " - Choose three relevant Bloom’s verbs that suit the abilities of {audience}.\n"
+ " - Write one measurable learning objective in Arabic that accurately reflects the subtopic’s purpose.\n"
+ " - **Track the chosen verb to prevent reusing it in later objectives.**\n\n"
+ "### Requirements for the Three Learning Domains\n"
+ "**Objectives must cover the three domains in a balanced way:**\n\n"
+ f"**1. Cognitive Domain (Knowledge):**\n"
+ f"{objectives_dimensions['Knowledge']['description']}\n"
+ "**Levels:**\n"
+ + "\n".join(
+ [
+ f" - {level['level_name']}: {level['description']}\n Verbs: {', '.join(level['verbs_examples'])}"
+ for level in objectives_dimensions["Knowledge"]["levels"]
+ ]
+ )
+ + "\n\n"
+ f"**2. Affective Domain (Attitude/Ability):**\n"
+ f"{objectives_dimensions['Ability']['description']}\n"
+ "**Levels:**\n"
+ + "\n".join(
+ [
+ f" - {level['level_name']}: {level['description']}\n Verbs: {', '.join(level['verbs_examples'])}"
+ for level in objectives_dimensions["Ability"]["levels"]
+ ]
+ )
+ + "\n\n"
+ f"**3. Psychomotor Domain (Skills):**\n"
+ f"{objectives_dimensions['Skills']['description']}\n"
+ "**Levels:**\n"
+ + "\n".join(
+ [
+ f" - {level['level_name']}: {level['description']}\n Verbs: {', '.join(level['verbs_examples'])}"
+ for level in objectives_dimensions["Skills"]["levels"]
+ ]
+ )
+ + "\n\n"
+ "### Critical Requirement: Verb Diversity \n"
+ "**This is a top-priority rule that must be followed precisely:**\n\n"
+ "**Verb Non-Repetition Rules:**\n"
+ "1. **Maximize verb diversity** — each objective should ideally use a different verb than all previous ones.\n"
+ "2. **Before selecting a verb, check:** Have I used this verb before? If yes, choose another.\n"
+ "3. **Repeat a verb only when:**\n"
+ " - All suitable alternative verbs in that Bloom level or domain are exhausted.\n"
+ " - The subtopic’s content explicitly requires that verb for accuracy.\n"
+ " - You can justify why no other verb fits.\n"
+ "4. **Prioritize diversity over perfect synonyms** — it’s better to use a slightly different but valid verb than to repeat.\n"
+ "5. **Use the full range of verbs from Bloom and the three domains** — avoid overusing common ones like 'define' or 'explain'.\n"
+ "6. **Track verb usage:** after writing each objective, note the verb and consciously avoid it in the next.\n"
+ "7. **If repetition is necessary:**\n"
+ " - Space it out by at least 3–5 objectives.\n"
+ " - Add a justification note in your internal reasoning.\n"
+ " - Try using it in a different context or content area.\n\n"
+ "### The 12 Mandatory Design Standards — Each Objective Must Meet All\n"
+ "**Based on the detailed objectives reference document:**\n\n"
+ "1. **Linked to the general goal:**\n"
+ " - Every objective must connect to the course’s overall goal.\n"
+ " - Example: If the general goal is 'Understand the concept of e-learning', "
+ "the specific objective could be 'The trainee accurately defines e-learning.'\n\n"
+ "2. **Measurable:**\n"
+ " - Objectives must be assessable using measurable performance indicators or outcomes.\n"
+ " - Correct: 'The trainee compares synchronous and asynchronous learning accurately.'\n"
+ " - Incorrect: 'The trainee understands e-learning.' (Not measurable)\n\n"
+ "3. **Achievable:**\n"
+ " - Realistic, suitable for learner ability and course duration.\n"
+ " - Correct: 'The trainee applies the steps to create a learning management account.'\n"
+ " - Incorrect: 'The trainee develops a full e-learning system in one hour.' (Unrealistic)\n\n"
+ "4. **Covers all three domains (Cognitive, Psychomotor, Affective):**\n"
+ " - Cognitive: 'The trainee defines e-learning accurately.'\n"
+ " - Psychomotor: 'The trainee practices using LMS assessment tools.'\n"
+ " - Affective: 'The trainee demonstrates interest in participating in e-learning activities.'\n\n"
+ "5. **Aligned with Bloom’s hierarchy:**\n"
+ " - Objectives must progress logically from lower to higher levels (Remember → Create).\n\n"
+ "6. **Clarity and precision:** Objective must be completely clear and specific.\n\n"
+ "7. **Free from ambiguity:** No vague or overly complex phrasing.\n\n"
+ "8. **Vocabulary clarity:** All terms must be understandable to {audience}.\n\n"
+ "9. **Single, focused goal:** Each objective expresses only one learning outcome.\n"
+ " - Correct: 'The trainee identifies the components of a virtual classroom.'\n"
+ " - Incorrect: 'The trainee identifies and applies virtual classroom components.'\n\n"
+ "10. **Realistic and feasible:** Achievable within program time and resources.\n\n"
+ "11. **Consistent with program outcomes:** Must align with the general and specific learning outcomes.\n\n"
+ "12. **Content-linked:** Directly related to the unit or module content.\n\n"
+ "### Objective Writing Rules\n"
+ "- One objective per subtopic — no more, no less.\n"
+ "- Each must directly and precisely reflect the subtopic’s purpose.\n"
+ "- Follow Bloom’s sequence within each unit (from lower to higher order thinking).\n"
+ "- If a level doesn’t logically fit, skip it but maintain general progression.\n"
+ "- You may combine two levels (e.g., Understand + Apply) if justified by subtopic purpose.\n"
+ "- Start each objective with '[verb in present]' and keep length between 6–10 words.\n"
+ "- Use verbs suitable for {audience} — e.g., children cannot 'evaluate' or 'analyze' like professionals.\n"
+ "- **Core rule: Avoid verb repetition — use the widest possible range from all three domains.**\n"
+ "- Ensure objectives are **measurable** and **achievable**.\n"
+ "- Maintain linguistic clarity — no vague or double meanings.\n"
+ "- Each objective must express only one precise learning outcome.\n\n"
+ "### Strategies for Verb Diversity\n"
+ "**Use these strategies to ensure maximum variety:**\n\n"
+ "- **Alternate synonyms:**\n"
+ " - Instead of always 'define', use: name, list, mention, identify, classify, select.\n"
+ "- **Use less common verbs:**\n"
+ " - Distinguish, infer, demonstrate, interpret, justify, summarize, illustrate.\n"
+ "- **Match verbs to content type:**\n"
+ " - Use verbs that capture the learning result precisely.\n"
+ "- **Consult the full domain verb lists** (above) with 5–7 verbs per level.\n"
+ "- **Distribute objectives across the three domains** — avoid focusing only on the cognitive domain.\n\n"
+ "### Examples of Correct and Incorrect Objectives\n\n"
+ "**Correct Examples (Good verb diversity and domain balance):**\n"
+ "1. (Cognitive - Remember): The trainee lists five types of e-learning platforms.\n"
+ "2. (Cognitive - Understand): The trainee distinguishes between various digital assessment tools.\n"
+ "3. (Cognitive - Apply): The trainee applies active learning strategies in the classroom.\n"
+ "4. (Cognitive - Understand): The trainee infers the main benefits of blended learning.\n"
+ "5. (Psychomotor - Practice): The trainee practices designing an interactive learning activity.\n"
+ "6. (Affective - Respond): The trainee actively participates in collaborative learning discussions.\n"
+ "7. (Cognitive - Analyze): The trainee compares different instructional design models.\n"
+ "8. (Psychomotor - Adapt): The trainee adjusts learning activities to meet learner needs.\n\n"
+ "**Incorrect Examples (Verb repetition — avoid this):**\n"
+ "1. The trainee defines the types of e-learning platforms.\n"
+ "2. The trainee defines digital assessment tools.\n"
+ "3. The trainee defines active learning strategies.\n"
+ "4. The trainee defines blended learning benefits.\n"
+ "5. The trainee defines steps of activity design.\n\n"
+ "**Unclear or Unmeasurable Objectives:**\n"
+ "- 'The trainee understands e-learning.' (Vague, not measurable)\n"
+ "- 'The trainee learns how to use tools.' (Unclear — which tools?)\n"
+ "- 'The trainee becomes an expert in instructional design.' (Unrealistic, not measurable)\n\n"
+ "**Improved Versions:**\n"
+ "- 'The trainee accurately defines e-learning.'\n"
+ "- 'The trainee effectively uses LMS tools.'\n"
+ "- 'The trainee applies instructional design principles to create a learning unit.'\n\n"
+ "### Critical Quality Checklist — Verify Before Finalizing Each Objective:\n"
+ "1. ✓ Is it clear and accurately expresses the intended outcome?\n"
+ "2. ✓ Does it align with a Bloom’s level or learning domain?\n"
+ "3. ✓ Is it free from ambiguity?\n"
+ "4. ✓ Is all vocabulary appropriate for {audience}?\n"
+ "5. ✓ Does it express only one learning outcome?\n"
+ "6. ✓ Is it measurable through observable performance?\n"
+ "7. ✓ Is it realistic and achievable?\n"
+ "8. ✓ Does it align with the overall outcomes?\n"
+ "9. ✓ Is it directly linked to the subtopic content?\n"
+ "10. ✓ Is it sequenced logically (simple → complex)?\n"
+ "11. ✓ Is it suitable for the learners’ level?\n"
+ "12. ✓ Do all objectives collectively cover knowledge, skills, and attitudes?\n"
+ "**13. Verb Check: Have you reused this verb? If yes, can you replace it?**\n"
+ "**14. Domain Check: Are the objectives balanced across all three domains?**\n\n"
+ "### Self-Reflection Requirement\n"
+ "After generating all objectives for a unit, pause and evaluate:\n"
+ "- Do objectives progress logically through Bloom’s levels?\n"
+ "- **How many unique verbs did you use? Any repetition?**\n"
+ "- **Can any repeated verbs be replaced with alternatives?**\n"
+ "- Are verbs diverse and contextually appropriate?\n"
+ "- **Do objectives cover all three domains evenly?**\n"
+ "- Can an external evaluator assess each objective clearly?\n"
+ "- Are all objectives realistic for {audience} and course duration?\n\n"
+ "### Final Verification: Verb Diversity & Domain Balance\n"
+ "**Before submitting your final output:**\n"
+ "1. Count how many times each verb appears.\n"
+ "2. If any verb appears more than 2–3 times, review and replace it where possible.\n"
+ "3. Aim for at least 70–80% unique verbs across the entire curriculum.\n"
+ "4. Keep a mental record of verb use for ongoing awareness.\n"
+ "5. **Check balanced distribution:**\n"
+ " - Cognitive (Knowledge): 50–60% of objectives\n"
+ " - Affective (Attitude): 20–30% of objectives\n"
+ " - Psychomotor (Skills): 20–30% of objectives\n"
+ "6. If imbalance occurs, revisit and adjust classifications.\n\n"
+ "### Domain-Specific Guidelines\n\n"
+ "**When writing Cognitive (Knowledge) objectives:**\n"
+ "- Use for topics focused on information, understanding, applying, analyzing, evaluating, or creating.\n"
+ "- Examples: 'The trainee defines...', 'The trainee compares...', 'The trainee designs...'.\n\n"
+ "**When writing Affective (Attitude) objectives:**\n"
+ "- Use for topics involving values, emotions, interests, or behaviors.\n"
+ "- Examples: 'The trainee demonstrates interest in...', 'The trainee participates actively...', 'The trainee commits to...'.\n\n"
+ "**When writing Psychomotor (Skills) objectives:**\n"
+ "- Use for topics requiring physical, technical, or procedural performance.\n"
+ "- Examples: 'The trainee practices...', 'The trainee performs...', 'The trainee innovates...'.\n\n"
+ "### Final Important Notes\n"
+ "- **Top Priority:** Verb diversity and balanced domain distribution.\n"
+ "- **Quality over quantity:** One well-crafted, diverse objective is better than several repetitive ones.\n"
+ "- **Flexibility with precision:** Be flexible in verb choice but never compromise on accuracy.\n"
+ "- **Continuous review:** Revisit objectives regularly for diversity and balance.\n"
+ "- **Context matters:** Always choose the verb that best reflects what the learner should achieve in that specific subtopic.\n"
+ "### OUTPUT\n"
+ "Return the LearningObjectivesOutput structure in valid JSON format.\n\n"
+ ),
+ expected_output="""JSON object with this structure:
+ {
+ "objectives": [
+ {
+ "unit": "Unit title",
+ "unit_description": "Brief summary of the unit scope",
+ "subtopic": "subtopic title",
+ "module_description": "Brief summary of what this subtopic covers",
+ "level": "Bloom's level assigned based on subtopic analysis",
+ "verbs": ["verb1", "verb2", "verb3"],
+ "objective": "One measurable Arabic objective"
+ }
+ ]
+ }""",
+ output_json=LearningObjectivesOutput,
+ agent=objectives_agent,
+ human_input=False,
+ )
diff --git a/agents/analysis_phase/outcomes.py b/agents/analysis_phase/outcomes.py
new file mode 100644
index 0000000000000000000000000000000000000000..4cb074c25cfd6f69fb453a2fd50e340b3d15f762
--- /dev/null
+++ b/agents/analysis_phase/outcomes.py
@@ -0,0 +1,308 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm_g
+from schemas import LearningOutcomesOutput
+
+def outcomes_generator():
+ model=llm_g()
+ return Agent(
+ role="Expert DNA-Based Learning Outcomes Designer",
+ goal="\n".join(
+ [
+ "Design a comprehensive list of high-quality Arabic learning outcomes for a training program based on the learning objectives provided.",
+ "Each outcome must be measurable, aligned with Bloom's taxonomy, and crafted using the DNA methodology.",
+ "",
+ "### CRITICAL RULES FOR OUTCOMES:",
+ "",
+ "**1. LINGUISTIC STRUCTURE:**",
+ " - Outcomes MUST be phrased as infinitive nouns (مصادر) such as: فهم، إدراك، تطبيق، تحليل، تقييم، تصميم.",
+ " - Use the verbal noun form (المصدر) not the verb itself.",
+ " - Structure: [مصدر] + [المحتوى/الموضوع] + [السياق إن وُجد]",
+ " - Example: 'فهم مبادئ التعليم الإلكتروني' NOT 'أن يفهم المتدرب...'",
+ "",
+ "**2. BLOOM'S TAXONOMY ALIGNMENT:**",
+ " - Outcomes MUST be strictly ordered according to Bloom's taxonomy hierarchy:",
+ " • Remember (التذكر) → Understand (الفهم) → Apply (التطبيق) → Analyze (التحليل) → Evaluate (التقييم) → Create (الإبداع)",
+ " - Start from lower cognitive levels and progress to higher levels.",
+ " - Each outcome must accurately reflect its assigned Bloom's level.",
+ " - Use appropriate verbal nouns (مصادر) that match the cognitive level.",
+ "",
+ "**3. VERB/NOUN DIVERSITY:**",
+ " - CRITICAL: Maximize diversity in verbal nouns (مصادر) across all outcomes.",
+ " - Avoid repeating the same مصدر unless absolutely necessary.",
+ " - Use synonyms and varied expressions within the same Bloom's level.",
+ " - Track usage to ensure maximum variety throughout the outcomes list.",
+ "",
+ "**4. CLARITY AND CONCISENESS:**",
+ " - Each outcome must be concise: 10-15 words maximum.",
+ " - Use clear, unambiguous language appropriate for {audience}.",
+ " - Avoid complex grammatical structures or nested phrases.",
+ " - Ensure smooth, natural Arabic flow.",
+ "",
+ "**5. MEASURABILITY:**",
+ " - Every outcome must be observable and measurable.",
+ " - The outcome should clearly indicate what success looks like.",
+ " - Avoid vague or abstract outcomes that cannot be assessed.",
+ "",
+ "**6. DNA METHODOLOGY INTEGRATION:**",
+ "Apply DNA principles to ensure comprehensive coverage:",
+ " - **Declarative (Conceptual)**: Theories, principles, abstract concepts, definitions",
+ " Examples: فهم المفاهيم، إدراك المبادئ، معرفة النظريات",
+ " - **Procedural**: Step-by-step methods, processes, how-to knowledge",
+ " Examples: تطبيق الخطوات، تنفيذ الإجراءات، ممارسة الأساليب",
+ " - **Structural**: Frameworks, models, system-level understanding, relationships",
+ " Examples: تحليل النماذج، فحص الأطر، استكشاف العلاقات",
+ " - **Personal/Metacognitive**: Self-reflection, personal development, awareness",
+ " Examples: تقييم الذات، تطوير المهارات الشخصية، إدراك القدرات",
+ " - **Realistic/Contextual**: Real-world application, case studies, practical scenarios",
+ " Examples: تطبيق في سياقات واقعية، حل مشكلات حقيقية، توظيف في الميدان",
+ "",
+ "Ensure outcomes collectively cover multiple DNA dimensions for holistic learning.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "You are an elite instructional designer specializing in outcomes-based education and the DNA knowledge framework.",
+ "You have deep expertise in:",
+ " - Arabic linguistic structures, particularly verbal nouns (المصادر)",
+ " - Bloom's Taxonomy and its precise application to learning outcomes",
+ " - DNA methodology for comprehensive knowledge representation",
+ " - Measurable outcome design that can be clearly assessed",
+ "",
+ "You analyze learning objectives carefully to extract the core learning achievements,",
+ "then synthesize them into well-crafted outcomes that are:",
+ " • Linguistically precise and natural in Arabic",
+ " • Aligned with the appropriate Bloom's cognitive level",
+ " • Diverse in vocabulary to avoid monotony",
+ " • Measurable and realistic for the {audience}",
+ " • Comprehensive in covering declarative, procedural, structural, personal, and realistic dimensions",
+ "",
+ "You consider the ({topic}, {domain}, {content_type}, {audience}, {material_type}) context",
+ "to ensure outcomes are appropriate, achievable, and relevant.",
+ "",
+ "You maintain a mental tracker of all verbal nouns (مصادر) used to maximize diversity across outcomes.",
+ ]
+ ),
+ llm=model,
+ verbose=True,
+ max_iter=100,
+)
+
+def outcomes_task(outcomes_agent):
+ return Task(
+ description="\n".join(
+ [
+ "You are given a set of learning objectives in: {objectives}.",
+ "",
+ "Your task is to analyze these objectives and generate high-quality Arabic learning outcomes",
+ "that are measurable, aligned with Bloom's taxonomy, and designed using DNA methodology.",
+ "",
+ "### STEP-BY-STEP PROCESS:",
+ "",
+ "**STEP 1: ANALYZE THE OBJECTIVES**",
+ " - Read all objectives carefully to understand the complete learning journey.",
+ " - Identify the main knowledge domains, skills, and behaviors covered.",
+ " - Group objectives by Bloom's taxonomy levels.",
+ " - Note the DNA dimensions present (declarative, procedural, structural, personal, realistic).",
+ "",
+ "**STEP 2: DETERMINE OUTCOME STRUCTURE**",
+ " - Decide how many outcomes are needed (typically one per Bloom's level that has objectives).",
+ " - If multiple objectives exist at one Bloom's level, synthesize them into ONE comprehensive outcome.",
+ " - Ensure outcomes progress logically from Remember → Create.",
+ "",
+ "**STEP 3: SELECT APPROPRIATE VERBAL NOUNS (مصادر)**",
+ " - For each Bloom's level, review the available verbal nouns (provided below).",
+ " - Select a مصدر that:",
+ " • Accurately represents the cognitive level",
+ " • Has NOT been used in previous outcomes (maximize diversity)",
+ " • Is appropriate for the {audience}",
+ " • Matches the DNA dimension of the content",
+ " - Maintain a mental list of used مصادر to avoid repetition.",
+ "",
+ "**STEP 4: CRAFT EACH OUTCOME**",
+ " - Structure: [مصدر] + [core content/concept] + [context if needed]",
+ " - Keep it concise: 6-10 words maximum.",
+ " - Ensure it's measurable and observable.",
+ " - Use natural, flowing Arabic.",
+ " - Verify it synthesizes all related objectives at that level.",
+ "",
+ "**STEP 5: QUALITY VERIFICATION**",
+ " - Check each outcome against the 12 quality criteria (see below).",
+ " - Ensure verb diversity across all outcomes.",
+ " - Verify Bloom's sequence is maintained.",
+ " - Confirm DNA dimensions are covered.",
+ "",
+ "### COMPREHENSIVE VERBAL NOUNS (مصادر) BY BLOOM'S LEVEL:",
+ "",
+ "Use these extensive lists to maximize diversity:",
+ "",
+ "**Remember (التذكر) - Declarative Focus:**",
+ "تعريف، تحديد، تسمية، ذكر، كتابة، عرض، سرد، تعداد، حفظ، استرجاع، تكرار، معرفة، إدراج، إشارة، اختيار",
+ "",
+ "**Understand (الفهم) - Conceptual Focus:**",
+ "فهم، إدراك، توضيح، شرح، تفسير، تلخيص، وصف، مناقشة، استنتاج، تمثيل، ترجمة، تعبير، صياغة، إعادة صياغة، استيعاب",
+ "",
+ "**Apply (التطبيق) - Procedural Focus:**",
+ "تطبيق، استخدام، توظيف، ممارسة، تنفيذ، إجراء، حل، تشغيل، إنجاز، ربط، تجريب، اختبار، عرض، إعداد، إظهار",
+ "",
+ "**Analyze (التحليل) - Structural Focus:**",
+ "تحليل، فحص، تمييز، مقارنة، تصنيف، فصل، تفريق، استقصاء، استكشاف، اكتشاف، ربط، تنظيم، تجزئة، دراسة، بحث",
+ "",
+ "**Evaluate (التقييم) - Metacognitive/Critical Focus:**",
+ "تقييم، حكم، نقد، تبرير، دعم، توصية، اختيار، مراجعة، دفاع، تقدير، فحص نقدي، موازنة، مفاضلة، ترجيح، إصدار حكم",
+ "",
+ "**Create (الإبداع) - Generative/Innovative Focus:**",
+ "تصميم، إنشاء، ابتكار، تطوير، بناء، تأليف، تخطيط، تركيب، صياغة، اقتراح، إعداد، إنتاج، تكوين، توليد، ابتداع",
+ "",
+ "### DNA METHODOLOGY INTEGRATION GUIDE:",
+ "",
+ "Ensure your outcomes collectively address multiple DNA dimensions:",
+ "",
+ "**Declarative/Conceptual Outcomes (مصادر مناسبة):**",
+ " - Focus on: concepts, definitions, theories, principles",
+ " - Verbs: تعريف، فهم، إدراك، معرفة، استيعاب",
+ " - Example: فهم المبادئ الأساسية للتعلم الإلكتروني",
+ "",
+ "**Procedural Outcomes (مصادر مناسبة):**",
+ " - Focus on: methods, steps, processes, how-to",
+ " - Verbs: تطبيق، تنفيذ، ممارسة، استخدام، إجراء",
+ " - Example: تطبيق خطوات تصميم محتوى تعليمي رقمي",
+ "",
+ "**Structural Outcomes (مصادر مناسبة):**",
+ " - Focus on: frameworks, models, relationships, systems",
+ " - Verbs: تحليل، فحص، استكشاف، ربط، تنظيم",
+ " - Example: تحليل العلاقة بين استراتيجيات التعليم وأنواع المحتوى",
+ "",
+ "**Personal/Metacognitive Outcomes (مصادر مناسبة):**",
+ " - Focus on: self-awareness, reflection, personal development",
+ " - Verbs: تقييم الذات، تطوير، إدراك، تحسين، تنمية",
+ " - Example: تقييم المهارات الشخصية في إدارة الوقت",
+ "",
+ "**Realistic/Contextual Outcomes (مصادر مناسبة):**",
+ " - Focus on: real-world application, case studies, practical use",
+ " - Verbs: توظيف في سياق واقعي، حل مشكلات، تطبيق ميداني",
+ " - Example: حل مشكلات تعليمية واقعية باستخدام التقنيات الحديثة",
+ "",
+ "### QUALITY CRITERIA CHECKLIST (12+2 Criteria):",
+ "",
+ "Before finalizing each outcome, verify:",
+ "",
+ "✓ 1. **Correct linguistic form**: Uses مصدر (infinitive noun), not verb",
+ "✓ 2. **Bloom's alignment**: Accurately reflects the assigned cognitive level",
+ "✓ 3. **Clear and unambiguous**: No vague or confusing language",
+ "✓ 4. **Appropriate vocabulary**: Suitable for {audience} level",
+ "✓ 5. **Single focus**: Expresses ONE outcome, not multiple combined",
+ "✓ 6. **Measurable**: Can be observed or assessed",
+ "✓ 7. **Realistic**: Achievable within program scope and time",
+ "✓ 8. **Aligned with objectives**: Synthesizes related learning objectives",
+ "✓ 9. **Content-relevant**: Directly relates to {topic} and {domain}",
+ "✓ 10. **Logical sequence**: Follows Bloom's order (low to high)",
+ "✓ 11. **Audience-appropriate**: Matches {audience} capabilities",
+ "✓ 12. **Comprehensive**: Covers knowledge, skills, attitudes collectively",
+ "✓ 13. **DIVERSE VOCABULARY**: Avoids repetition of مصادر",
+ "✓ 14. **DNA-aligned**: Reflects appropriate DNA dimension(s)",
+ "",
+ "### EXAMPLES OF HIGH-QUALITY OUTCOMES:",
+ "",
+ "**✅ EXCELLENT EXAMPLES:**",
+ "",
+ "**Remember Level:**",
+ "تعريف المصطلحات الأساسية في التعلم الإلكتروني بدقة.",
+ "(Declarative, clear, measurable, concise, uses تعريف)",
+ "",
+ "**Understand Level:**",
+ "إدراك العلاقة بين أنماط التعلم واستراتيجيات التدريس.",
+ "(Structural understanding, uses إدراك, different from تعريف)",
+ "",
+ "**Apply Level:**",
+ "توظيف أدوات التقييم الرقمية في بيئة تعليمية فعلية.",
+ "(Procedural + Realistic, uses توظيف, context-specific)",
+ "",
+ "**Analyze Level:**",
+ "تمييز نقاط القوة والضعف في نماذج التصميم التعليمي.",
+ "(Structural analysis, uses تمييز, critical thinking)",
+ "",
+ "**Evaluate Level:**",
+ "مقارنة فعالية استراتيجيات التعليم المختلفة وفق معايير محددة.",
+ "(Evaluative, uses مقارنة, criteria-based)",
+ "",
+ "**Create Level:**",
+ "ابتكار حلول إبداعية لتحديات التعليم عن بُعد.",
+ "(Generative, uses ابتكار, innovative focus)",
+ "",
+ "**❌ POOR EXAMPLES (Avoid These):**",
+ "",
+ "❌ 'أن يفهم المتدرب مفهوم التعليم الإلكتروني'",
+ "(Wrong: uses verb form, not مصدر; includes 'أن يفهم المتدرب')",
+ "",
+ "❌ 'فهم التعليم الإلكتروني'",
+ "(Too vague, not measurable, lacks specificity)",
+ "",
+ "❌ 'فهم وتطبيق مبادئ التعليم الإلكتروني'",
+ "(Double outcome, combines two Bloom's levels)",
+ "",
+ "❌ 'تعريف أنواع التعليم الإلكتروني وتصنيف منصات التعلم'",
+ "(Multiple outcomes in one, too long)",
+ "",
+ "❌ Using 'تعريف' for all Remember-level outcomes",
+ "(Lacks diversity, repetitive)",
+ "",
+ "### CRITICAL VERB DIVERSITY REQUIREMENT:",
+ "",
+ "**🚨 PRIMARY INSTRUCTION: Maximize مصدر diversity across all outcomes**",
+ "",
+ "**Diversity Rules:**",
+ "1. Before selecting a مصدر, check: Have I used this before?",
+ "2. If yes, select an alternative unless no suitable synonym exists.",
+ "3. Use the full range of available مصادر at each Bloom's level.",
+ "4. Aim for 80-100% unique مصادر across all outcomes.",
+ "5. Track usage mentally as you craft each outcome.",
+ "",
+ "**Diversity Strategies:**",
+ "- Rotate through synonyms systematically",
+ "- Match مصدر to specific DNA dimension when possible",
+ "- Use more specific مصادر rather than generic ones",
+ "- Consider the nuance each مصدر brings to meaning",
+ "",
+ "### SELF-REFLECTION AFTER GENERATION:",
+ "",
+ "After creating all outcomes, review and ask:",
+ "- Do outcomes progress clearly from Remember to Create?",
+ "- Is there good diversity in مصادر (minimal repetition)?",
+ "- Do outcomes collectively cover DNA dimensions?",
+ "- Are all outcomes measurable and realistic for {audience}?",
+ "- Does each outcome synthesize its related objectives effectively?",
+ "- Is the Arabic natural, clear, and linguistically correct?",
+ "- Would an evaluator be able to assess achievement of each outcome?",
+ "",
+ "### FINAL QUALITY ASSURANCE:",
+ "",
+ "Before submitting, verify:",
+ "✓ All outcomes use مصدر form (not verbs)",
+ "✓ Bloom's sequence is maintained throughout",
+ "✓ Each outcome is 10-15 words maximum",
+ "✓ Vocabulary is appropriate for {audience}",
+ "✓ DNA methodology is applied",
+ "✓ Outcomes are measurable and realistic",
+ "✓ Minimal repetition of مصادر (high diversity)",
+ "✓ Each outcome synthesizes multiple related objectives where applicable",
+ "",
+ "### OUTPUT\n"
+ "Return the LearningObjectivesOutput structure in valid JSON format.\n\n",
+ ]
+ ),
+ expected_output="""JSON object with this structure:
+ {
+ "objectives": [
+ {
+ "unit": "Unit title",
+ "unit_description": "Brief summary of the unit scope",
+ "unit_outcome": "One measurable Arabic objective derived from the unit description and its subtopics and their purposes",
+ }
+ ],
+ }""",
+ output_json=LearningOutcomesOutput,
+ agent=outcomes_agent,
+ human_input=False,
+)
diff --git a/agents/analysis_phase/outliner.py b/agents/analysis_phase/outliner.py
new file mode 100644
index 0000000000000000000000000000000000000000..82dae0eeaef509fceccfa57cb6131076163e7487
--- /dev/null
+++ b/agents/analysis_phase/outliner.py
@@ -0,0 +1,100 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+#from schemas import CurriculumOutline
+
+# ========= 4. Outline Agent =========
+def outline_agent():
+ model=llm()
+ return Agent(
+ role="Scientific Outline Generator",
+ goal="\n".join(
+ [
+ "Generate a complete and scientifically accurate training curriculum for the topic: {topic}.",
+ "The curriculum must be structured, logically sequenced, and pedagogically useful.",
+ "Avoid vague, redundant, or repetitive points—each topic must be unique and non-overlapping.",
+ "Ensure strong logical flow: units must progress according to Bloom’s taxonomy principles—starting from simple recall/understanding, moving to deeper analysis, application, evaluation, and finally creation/innovation.",
+ "Important: Do NOT explicitly use Bloom verbs (e.g., analyze, evaluate, create). Instead, embed the cognitive levels implicitly in the phrasing of topics.",
+ "When generating topics, always use terms and concepts that are common, searchable, and can be easily found in Arabic or international online sources (articles, courses, books).",
+ "Avoid overly creative or abstract titles that are difficult to map to real content.",
+ "Follow this strict format:",
+ "- Output must be in JSON.",
+ "- Curriculum must include exactly 4 units.",
+ "- Each unit must have exactly 5 sub-topics.",
+ "- Units must be output with keys: unit_title, topics.",
+ "Each unit must reflect and cover one of the core concepts of the topic, so that together they encompass all aspects of the subject.",
+ "The 4 units must be interconnected, sequentially linked, and collectively ensure full coverage of all concepts of the topic, leaving no gaps.",
+ "Ensure all text is written in **Arabic language**.",
+ "Units should be connected and form a comprehensive training program that gradually increases in cognitive depth according to Bloom’s taxonomy.",
+ "Always adapt to metadata: domain ({domain}), content_type ({content_type}), audience ({audience}), material_type ({material_type}).",
+ "Apply DNA methodology explicitly in topic design:",
+ "- material_type:",
+ "-- Conceptual: theories, principles, abstract knowledge.",
+ "-- Procedural: step-by-step instructions or methods.",
+ "-- Structural: frameworks, models, or system views.",
+ "-- Personal: learner reflection, skills, or self-development aspects.",
+ "-- Realistic: real-world examples, applications, or case studies.",
+ "- content_type:",
+ "-- Educational → for structured learning (e.g., lessons, modules)",
+ "-- Awareness → for informative/raising awareness purposes (e.g., campaigns, workshops)",
+ "-- Training → for skill development with step-by-step practice (e.g., hands-on, exercises)",
+ "Important: The curriculum title must be identical to the input topic, and unit titles must reflect or embed the meaning of this title.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "This agent acts as both a scientific researcher and curriculum designer.",
+ "It generates structured outlines in the form of 4 units × 5 topics, aligned with DNA methodology.",
+ "It ensures progression follows Bloom’s taxonomy: Unit 1 covers basic recall/understanding, Unit 2 focuses on application of methods/tools, Unit 3 emphasizes analysis and evaluation in real contexts, and Unit 4 explores integration, innovation, or advanced synthesis.",
+ "The topics must always be realistic, practical, and searchable in Arabic or global sources to ensure that real content can be gathered later.",
+ "The final output must always be in Arabic.",
+ "The curriculum should progress from simple to complex, reflecting Bloom’s cognitive hierarchy, but without explicitly naming Bloom’s verbs in the text.",
+ ]
+ ),
+ llm=model,
+ verbose=True,
+ reasoning=True,
+ max_reasoning_attempts=3,
+ max_iter=100,
+)
+
+
+# ========= 5. Task =========
+def outline_task(outline_agent):
+ return Task(
+ description="\n".join(
+ [
+ "Generate a structured outline for the topic: {topic}.",
+ "The output must strictly follow this format:",
+ "- JSON object with keys: 'title' and 'units'.",
+ "- 'title': must be exactly the same as the input topic (in Arabic).",
+ "- 'units': exactly 4 items.",
+ "- Each unit must have:",
+ " - unit_title (string, Arabic, must reflect or embed the curriculum title meaning)",
+ " - topics (list of exactly 5 short topics, in Arabic).",
+ "Ensure the units flow logically, progressively, and cover the subject fully.",
+ "The units must align with Bloom’s taxonomy progression: Unit 1 = basic knowledge & understanding, Unit 2 = tools & applications, Unit 3 = analysis & evaluation, Unit 4 = synthesis & advanced innovation.",
+ "Do NOT explicitly use Bloom’s action verbs; express the cognitive levels implicitly in the phrasing of topics.",
+ "Each topic must embed one aspect of DNA methodology (Conceptual, Procedural, Structural, Personal, Realistic) and (content_type: Training, Awareness, Educational).",
+ "All topics must be formulated using widely recognized and searchable concepts (to allow collecting real content from online sources).",
+ "Avoid repetition—no two topics should overlap in meaning.",
+ "Do not add extra fields outside the schema.",
+ "The entire output must be in Arabic.",
+ ]
+ ),
+ expected_output=(
+ "A valid JSON object with this structure:\n"
+ "{\n"
+ ' "title": "string (Arabic curriculum title)",\n'
+ ' "units": [\n'
+ " {\n"
+ ' "unit_title": "string (Arabic, must reflect the title)",\n'
+ ' "topics": ["topic1", "topic2", "topic3", "topic4", "topic5"]\n'
+ " }, ... (4 units total)\n"
+ " ]\n"
+ "}"
+ ),
+ #output_json=CurriculumOutline,
+ agent=outline_agent,
+)
diff --git a/agents/books/__init__.py b/agents/books/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ea4a40e52f7eb01c56e661511923ae8f5bc7121
--- /dev/null
+++ b/agents/books/__init__.py
@@ -0,0 +1,37 @@
+from .units_structure import (
+ course_structuring_agent,
+ course_structuring_task,
+)
+from .book_structure import (
+ book_structure_agent,
+ generate_book_outline_task,
+)
+from .book_planning import (
+ agent_task_planning
+)
+from .book_content import (
+ make_writer_crew,
+ make_quality_crew,
+)
+from .book_content_gpt import (
+ make_writer_crew_gpt,
+ make_quality_crew_gpt,
+)
+from .queries_agent import (
+ query_agent,
+ query_task,
+)
+from .units_intro import (
+ intro_generator,
+ intro_generation_task,
+)
+from .intro_plan import(
+ intro_style_planner,
+ intro_style_planner_task
+)
+from .auto_units_structure import (
+ book_units_langchain_agent,
+)
+from .book_content_new import (
+ make_writer_editor_crew
+)
\ No newline at end of file
diff --git a/agents/books/apa_agent.py b/agents/books/apa_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..4fddefdf4a2a69c9f591d7114049ef7dd32a9ed4
--- /dev/null
+++ b/agents/books/apa_agent.py
@@ -0,0 +1,160 @@
+import json
+from crewai import Agent, Task, Crew, Process
+from schemas.books.sources_schema import SourceMetadataAgentResult
+from modules import llm_oss_120b
+
+
+def run_metadata_agent(source: dict) -> dict:
+ """
+ Receives SourceForAgent as dict.
+ Extracts academic metadata with semantic understanding (no hallucination).
+ """
+
+ model = llm_oss_120b()
+
+ # =====================================================
+ # Agent
+ # =====================================================
+ metadata_agent = Agent(
+ name="SourceMetadataExtractor",
+ role="Academic bibliographic metadata analyst",
+ goal=(
+ "فهم النص الأكاديمي وتحليل بنيته "
+ "لاستخراج البيانات الببليوجرافية الصحيحة "
+ "من غير تخمين أو هلوسة."
+ ),
+ backstory=(
+ "أنت أخصائي فهرسة أكاديمية بخبرة طويلة. "
+ "تفهم شكل الكتب، الرسائل الجامعية، "
+ "الأبحاث، والتقارير المؤسسية حتى لو لم تُعنون صراحة. "
+ "تعتمد على الفهم البنيوي للنص "
+ "لكن ترفض أي معلومة غير مؤكدة."
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+ # =====================================================
+ # Task (Arabic – semantic but strict)
+ # =====================================================
+ metadata_task = Task(
+ name="Semantic extraction of academic bibliographic metadata",
+ description=(
+ "سيتم تزويدك بمصدر أكاديمي واحد بصيغة JSON.\n\n"
+ "============================\n"
+ "شكل بيانات الإدخال\n"
+ "============================\n"
+ "بيانات الإدخال عبارة عن كائن JSON يحتوي على المفاتيح التالية:\n\n"
+ "1) source_url:\n"
+ "- رابط الملف (للتوثيق فقط)\n\n"
+ "2) source_type:\n"
+ "- نوع تقني تقريبي (pdf / html)\n\n"
+ "3) domain:\n"
+ "- نطاق الموقع (قرينة ضعيفة)\n\n"
+ "4) text_pages:\n"
+ "- قائمة نصوص مستخرجة من أول صفحات المصدر\n"
+ "- هذا هو المصدر الحقيقي الوحيد للمعلومات\n\n"
+ "⚠️ تجاهل أي حقول أخرى إن وُجدت.\n\n"
+ "============================\n"
+ "مهم: كيفية فهم النص\n"
+ "============================\n"
+ "قد لا تكون البيانات مكتوبة بصيغة صريحة مثل:\n"
+ "«العنوان:» أو «المؤلف:».\n\n"
+ "مطلوب منك تحليل النص بنيويًا:\n"
+ "- العنوان: النص الذي يمثل اسم العمل كاملًا\n"
+ " (غالبًا في البداية، مميز، مكرر، أو منفصل)\n\n"
+ "- المؤلف:\n"
+ " اسم الشخص أو الجهة المسؤولة عن العمل نفسه\n"
+ " (وليس المشرف، وليس دار النشر)\n\n"
+ "- السنة:\n"
+ " اختر سنة النشر الصحيحة فقط\n"
+ " إذا وُجد أكثر من تاريخ:\n"
+ " ▪ استبعد التواريخ الهجرية\n"
+ " ▪ استبعد فترات دراسية\n"
+ " ▪ اختر السنة المرتبطة مباشرة بالنشر أو الإجازة العلمية\n\n"
+ "- الناشر / الجهة:\n"
+ " الجهة التي أصدرت العمل (جامعة، مجلة، مؤسسة)\n\n"
+ "============================\n"
+ "قواعد صارمة (لا يمكن كسرها)\n"
+ "============================\n"
+ "1) لا تُنشئ بيانات غير موجودة\n"
+ "2) لا تُصحح أخطاء لغوية أو OCR\n"
+ "3) لا تُكمل أسماء ناقصة\n"
+ "4) لا تعتمد على الرابط أو اسم الموقع\n"
+ "5) إذا وُجد شك → اعتبر المعلومة غير موجودة\n\n"
+ "============================\n"
+ "تصنيف نوع المصدر\n"
+ "============================\n"
+ "- book: كتاب مطبوع أو إلكتروني\n"
+ "- thesis: رسالة جامعية (ماجستير / دكتوراه)\n"
+ "- journal_article: مقال في مجلة علمية\n"
+ "- institutional_report: تقرير رسمي أو جامعي\n"
+ "- website: صفحة ويب\n\n"
+ "============================\n"
+ "التحقق من الصلاحية\n"
+ "============================\n"
+ "is_valid = true فقط إذا:\n"
+ "- يوجد عنوان مفهوم بوضوح\n"
+ "- يوجد مؤلف واحد على الأقل\n\n"
+ "غير ذلك:\n"
+ "- is_valid = false\n"
+ "- reason = سبب مختصر\n\n"
+ "============================\n"
+ "الإخراج\n"
+ "============================\n"
+ "- JSON فقط\n"
+ "- بدون شرح\n"
+ "- مطابق تمامًا لـ SourceMetadataAgentResult\n\n"
+ "============================\n"
+ "بيانات الإدخال:\n"
+ "{source}\n"
+ ),
+ expected_output="JSON مطابق لـ SourceMetadataAgentResult فقط.",
+ output_json=SourceMetadataAgentResult,
+ agent=metadata_agent,
+ )
+
+ # =====================================================
+ # Crew
+ # =====================================================
+ crew = Crew(
+ agents=[metadata_agent],
+ tasks=[metadata_task],
+ process=Process.sequential,
+ verbose=False,
+ memory=False,
+ )
+
+ result = crew.kickoff(inputs={"source": source})
+
+ tokens={}
+ if result.token_usage:
+ tokens = result.token_usage.dict()
+
+ # =====================================================
+ # Normalize output (SAFE)
+ # =====================================================
+ if hasattr(result, "json_dict"):
+ jd = result.json_dict
+ return (jd() if callable(jd) else jd), tokens
+
+ if hasattr(result, "model_dump"):
+ md = result.model_dump
+ return (md() if callable(md) else md), tokens
+
+ try:
+ parsed = json.loads(str(result))
+ if isinstance(parsed, dict):
+ return parsed, tokens
+ except Exception:
+ pass
+
+ return {
+ "is_valid": False,
+ "reason": "agent_output_unparseable",
+ "normalized_source_type": None,
+ "metadata": None,
+ "evidence": None,
+ }
diff --git a/agents/books/auto_units_structure.py b/agents/books/auto_units_structure.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a2ccd36dc00cadc19559415cec9f4a688956f7b
--- /dev/null
+++ b/agents/books/auto_units_structure.py
@@ -0,0 +1,123 @@
+from modules import model, llm_g
+import json
+import re
+from langchain_core.messages import SystemMessage, HumanMessage
+
+def book_units_langchain_agent(
+ topic: str,
+ units_number: int,
+ notes: str | None = None,
+ course_description: str | None = None,
+ course_audience: str | None = None,
+):
+
+ # ---------- Step 1 : Generate Markdown Outline ----------
+ llm = llm_g()
+
+ notes_block = ""
+ if notes:
+ notes_block = f"""
+Additional author notes (optional guidance):
+{notes}
+
+Use these notes to guide the course structure but do NOT copy them literally.
+"""
+
+ description_block = ""
+ if course_description:
+ description_block = f"""
+Book description (guidance):
+{course_description}
+
+Use it to understand the theme and depth of the course.
+Do NOT copy it literally in the output.
+"""
+
+ audience_block = ""
+ if course_audience:
+ audience_block = f"""
+Target audience (guidance):
+{course_audience}
+
+Use it to adapt the level and focus of the units.
+"""
+
+ result = llm.call(
+ f"""
+Create a structured outline for a professional course about [{topic}].
+
+The course should contain exactly {units_number} units.
+
+For each unit include:
+- Unit title
+- Learning outcome
+- Main topics
+
+{description_block}
+
+{audience_block}
+
+{notes_block}
+
+Return the outline in Markdown.
+Focus on logical learning progression.
+"""
+ )
+
+ # ---------- Step 2 : System Prompt for JSON extraction ----------
+ system_prompt = f"""
+Extract structured course data from the Markdown text.
+
+Return JSON with EXACTLY this structure:
+
+{{
+ "course_name": "{topic}",
+ "course_description": "string",
+ "course_audience": "string",
+ "learning_outcomes": [
+ "string"
+ ],
+ "units": [
+ {{
+ "unit_name": "string",
+ "outcome": "string",
+ "topics": [
+ "string"
+ ]
+ }}
+ ]
+}}
+
+Rules:
+
+- If course_description is missing, generate one
+- If course_audience is missing, generate one
+- Generate 4-6 topics per unit
+- Units must equal {units_number}
+- unit_name should look like: "الفصل الأول: ..."
+- topics must be short educational titles
+- Output ONLY valid JSON
+- No markdown
+- No explanations
+"""
+
+ # ---------- Step 3 : Call Model ----------
+ llm_model = model()
+
+ response = llm_model.invoke(
+ [
+ SystemMessage(content=system_prompt),
+ HumanMessage(content=result),
+ ]
+ )
+
+ raw_output = response.content.strip()
+
+ # ---------- Step 4 : Clean JSON ----------
+ try:
+ structured_data = json.loads(raw_output)
+ except json.JSONDecodeError:
+ cleaned = re.sub(r"```json|```", "", raw_output).strip()
+ structured_data = json.loads(cleaned)
+
+ return structured_data
diff --git a/agents/books/book_cohesion.py b/agents/books/book_cohesion.py
new file mode 100644
index 0000000000000000000000000000000000000000..8658c58c4878a94d1925d1c5e42e8fda54df6476
--- /dev/null
+++ b/agents/books/book_cohesion.py
@@ -0,0 +1,113 @@
+from crewai import Agent, Task
+from modules import llm_open_grok
+from schemas.books.book_cohesion import CohesionOutput
+COHESION_AGENT_SYSTEM = """
+[ROLE]
+أنت محرر سردي لكتاب عربي غير روائي.
+لا تُولّد معرفة جديدة، ولا تُعيد كتابة المحتوى من الصفر.
+مهمتك تحسين التماسك السردي والصوت الواحد عبر الفصول.
+
+────────────────────────────────
+[SCOPE – STRICT]
+────────────────────────────────
+- يُمنع إضافة أفكار جديدة أو أمثلة جديدة من عندك.
+- يُمنع حذف الأفكار الأساسية.
+- يُمنع تعديل الاستشهادات أو قائمة المصادر أو صيغها.
+- يُسمح فقط بـ:
+ 1) تعديل أول فقرة في كل فصل.
+ 2) تعديل آخر فقرة في كل فصل.
+ 3) إضافة جملة ربط واحدة عند الحاجة بين الفصول.
+ 4) إصلاح لغوي/ترقيم خفيف داخل الفقرتين المعدلتين فقط.
+
+
+────────────────────────────────
+[NARRATIVE GOALS]
+────────────────────────────────
+- جعل الفصول تُقرأ كجسد واحد لا كمقالات منفصلة.
+- تثبيت صوت المؤلف (نبرة واحدة) عبر الفصول.
+- ضمان تراكم فكري: ما ينتهي في فصل يمهّد لما بعده دون تكرار.
+- منع التكرار الافتتاحي المعتاد (التعريفات المتشابهة في كل فصل).
+
+────────────────────────────────
+[RESEARCH DIGESTION RULE – CRITICAL]
+────────────────────────────────
+- إذا كان المحتوى يتضمن عرضًا بحثيًا خامًا (أرقام/اختبارات/جداول):
+ لا تُدرج التفاصيل الرقمية داخل الفقرتين المعدلتين.
+ ركّز على "الدلالة" لا "البيانات".
+- لا تحذف المعلومة من جسم الفصل؛ فقط تجنب تضخيمها في المدخل/الخاتمة.
+
+────────────────────────────────
+[LANGUAGE & PUNCTUATION – STRICT]
+────────────────────────────────
+- العربية الفصحى المعاصرة.
+- استخدام الفاصلة (،) داخل الجملة.
+- الفاصلة المنقوطة (؛) عند الانتقال لتعليل/تفصيل.
+- النقطة (.) لإنهاء فكرة مكتملة.
+- لا جمل طويلة متكدسة؛ اجعل الإيقاع مقروءًا.
+
+────────────────────────────────
+[OUTPUT CONTRACT – STRICT]
+────────────────────────────────
+أخرج JSON فقط بالشكل التالي:
+{
+ "edited_chapters": [...],
+ "narrative_memory": {
+ "central_thread": "",
+ "current_voice": "",
+ "key_concepts_introduced": [],
+ "concepts_to_continue": [],
+ "do_not_repeat": [],
+ "tone_continuity_notes": ""
+ }
+}
+"""
+
+COHESION_TASK_INSTRUCTIONS = """
+[INPUT]
+{chunk_payload}
+ستستقبل:
+- book_meta
+- chapters_chunk (2-3 فصول عادة)
+- previous_narrative_memory (قد تكون null)
+
+
+[TASK]
+1) لكل فصل في chapters_chunk:
+ - عدّل فقط أول فقرة من أول محور/قسم يظهر فعليًا في النص (أول فقرة ضمن أول subsection موجود).
+ - وعدّل فقط آخر فقرة من آخر محور/قسم (آخر فقرة ضمن آخر subsection).
+ - إن لم يكن تقسيم الفقرات واضحًا: اعتبر أول 3-5 أسطر كـ "فقرة أولى" وآخر 3-5 أسطر كـ "فقرة أخيرة".
+2) لا تغيّر باقي النص.
+3) أضف جملة ربط واحدة فقط (عند الحاجة) في آخر فقرة من الفصل، تمهّد للفصل التالي.
+4) حدّث narrative_memory:
+ - central_thread: خيط واحد يصف مسار الكتاب حتى الآن بجملة.
+ - current_voice: وصف موجز لصوت الكاتب (مثل: "تفسيري مهني تطبيقي").
+ - key_concepts_introduced: أهم المصطلحات/الأفكار التي ظهرت لأول مرة في هذه الدفعة.
+ - concepts_to_continue: أفكار يجب استمرارها لاحقًا (تمهيد).
+ - do_not_repeat: جمل/تعريفات/افتتاحيات لا يجب تكرارها لاحقًا.
+ - tone_continuity_notes: ملاحظات قصيرة لضبط النبرة في الدفعة القادمة.
+
+[IMPORTANT]
+- لا تضف أي قسم جديد.
+- لا تلخص الفصول.
+- لا تكتب خارج JSON.
+"""
+
+def build_cohesion_agent():
+ model = llm_open_grok()
+ return Agent(
+ role="محرر سردي",
+ goal="تحسين التماسك السردي والصوت الواحد عبر الفصول دون إضافة محتوى جديد",
+ backstory=COHESION_AGENT_SYSTEM,
+ llm=model,
+ verbose=False,
+ allow_delegation=False,
+ )
+
+
+def build_cohesion_task(agent):
+ return Task(
+ description=COHESION_TASK_INSTRUCTIONS,
+ agent=agent,
+ expected_output="JSON فقط يحتوي edited_chapters و narrative_memory",
+ output_json=CohesionOutput,
+ )
diff --git a/agents/books/book_content.py b/agents/books/book_content.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6bf6633d29b88ec2454eb34c1dd5d4c64fc5bd3
--- /dev/null
+++ b/agents/books/book_content.py
@@ -0,0 +1,867 @@
+# -*- coding: utf-8 -*-
+"""
+Arabic Book Subsection Pipeline (CrewAI)
+- Writer (RAG-Strict + APA7 + Style-Exact)
+- Quality Gate (developmental edit + hard QA)
+- Optional JSON Contract Repair
+Compatible with Grok 4.1 fast style prompting (clear context, explicit goals, strict output contract).
+"""
+
+import os
+import re
+import json
+from typing import Any, Dict, List
+
+# ---------------------------------------------------------
+# Runtime flags
+# ---------------------------------------------------------
+os.environ["CREWAI_TRACING_ENABLED"] = "false"
+os.environ["CREWAI_DISABLE_TELEMETRY"] = "true"
+
+from crewai import Agent, Task, Crew, Process
+from modules import llm_4m, llm_open_grok
+
+# ---------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------
+
+
+def _to_text(result: Any) -> str:
+ """Normalize Crew result object to raw text."""
+ if result is None:
+ return ""
+ if hasattr(result, "raw") and isinstance(result.raw, str):
+ return result.raw.strip()
+ return str(result).strip()
+
+
+def extract_strict_json(text: str) -> Dict[str, Any]:
+ """
+ Extract the first JSON object from LLM output and validate contract.
+ Contract: {"generated_content": str, "sources": list[str]}
+ """
+ if not text:
+ return {"generated_content": "", "sources": []}
+
+ # fast path
+ try:
+ obj = json.loads(text)
+ return validate_contract(obj)
+ except Exception:
+ pass
+
+ # extract first JSON object
+ match = re.search(r"\{[\s\S]*\}", text)
+ if not match:
+ return {"generated_content": "", "sources": []}
+
+ blob = match.group(0)
+
+ # remove trailing commas before } or ]
+ blob = re.sub(r",\s*([}\]])", r"\1", blob)
+
+ try:
+ obj = json.loads(blob)
+ return validate_contract(obj)
+ except Exception:
+ return {"generated_content": "", "sources": []}
+
+
+def validate_contract(obj: Dict[str, Any]) -> Dict[str, Any]:
+ """Force exact output schema and safe types."""
+ if not isinstance(obj, dict):
+ return {"generated_content": "", "sources": []}
+
+ content = obj.get("generated_content", "")
+ sources = obj.get("sources", [])
+
+ if not isinstance(content, str):
+ content = str(content)
+
+ if not isinstance(sources, list):
+ sources = []
+
+ clean_sources: List[str] = []
+ for s in sources:
+ if isinstance(s, str):
+ s2 = s.strip()
+ if s2 and s2 not in clean_sources:
+ clean_sources.append(s2)
+
+ return {"generated_content": content.strip(), "sources": clean_sources}
+
+
+# ---------------------------------------------------------
+# Prompt blocks
+# ---------------------------------------------------------
+WRITER_DESCRIPTION = """
+أنت مؤلف كتاب عربي غير روائي، وتكتب محورًا فرعيًا واحدًا فقط.
+مهمتك إنتاج نص نهائي صالح للنشر، ملتزم حرفيًا بالخطة والنطاق،
+وبأسلوب تحليلي إنساني غير نمطي، لا يشبه الأوراق البحثية.
+تفضّل الكتابة التفسيرية التحفظية على ترك الناتج فارغًا.
+
+=================================================
+📌 مراعاة نوع الكتاب
+=================================================
+
+يجب أن يتكيّف أسلوب الشرح مع طبيعة موضوع الكتاب.
+
+أمثلة:
+
+- كتاب تدريبي (مثل تدريب كرة القدم):
+التركيز على التطبيق، الخطوات العملية، السيناريوهات التدريبية.
+
+- كتاب تعليمي:
+التركيز على الشرح المفاهيمي والأمثلة التوضيحية.
+
+- كتاب تحليلي أو فكري:
+التركيز على التحليل والتفسير والربط بين الأفكار.
+
+لا تستخدم نفس أسلوب العرض لجميع أنواع الكتب.
+
+=================================================
+📌 أولًا: وعي مستوى الكتاب (Book-Level Awareness)
+=================================================
+- النص جزء من كتاب متكامل، وليس فصلًا مستقلًا ولا ورقة بحثية.
+- يجب أن يحمل وعيًا ضمنيًا بمسار الكتاب العام دون تلخيصه.
+- يُمنع التعامل مع القسم أو المحور كوحدة مغلقة على ذاتها.
+- لا تكتب مقدمة عامة للكتاب ولا خاتمة عامة داخله.
+
+=================================================
+📌 ثانيًا: قاعدة الحسم عند التعارض (Decision Rule)
+=================================================
+إذا ظهر تعارض بين الخطة أو محدودية RAG أو متطلبات الأسلوب، فالأولوية تكون:
+1) الخطة أولًا
+2) RAG ثانيًا
+3) الأسلوب ثالثًا
+
+- اكتب تفسيرًا تحليليًا ضيقًا وملتزمًا بالخطة وRAG.
+- لا تترك الناتج فارغًا ما دام توجد مادة قابلة للتفسير.
+
+=================================================
+📌 ثالثًا: ترتيب الأولويات الإلزامي
+=================================================
+1) صحة JSON في المخرجات.
+2) الالتزام الحرفي بالخطة (Core Idea ثم Key Points).
+3) الالتزام الصارم بـ Scope Limit و Avoid Overlap With.
+4) RAG ONLY كمصدر للمعلومة.
+5) سلامة اللغة والترقيم.
+6) جودة الأسلوب والسبك.
+7) عمق تحليلي مناسب دون حشو.
+
+=================================================
+📌 رابعًا: الخطة عقد مُلزم (Plan Binding Contract)
+=================================================
+- Core Idea يجب أن تكون واضحة وصريحة داخل النص.
+- كل Key Point تُعالج صراحة في فقرة مستقلة.
+- أي خروج عن Scope Limit = مخالفة تحريرية.
+- أي تداخل مع Avoid Overlap With = خطأ جسيم.
+- إذا لم تُغطَّ جميع Key Points فالناتج غير صالح.
+
+=================================================
+📌 خامسًا: قواعد الفقرات والبناء الداخلي
+=================================================
+1) قبل كل فقرة، اربطها داخليًا بـ Key Point أو Core Idea.
+2) كل فقرة = فكرة تحليلية واحدة فقط (Paragraph Atomicity).
+3) عند الانتقال لفكرة جديدة، أنهِ الفكرة السابقة دلاليًا أولًا.
+4) يمنع البدء المباشر بشرح Subsection Title.
+5) ابدأ بفقرة تمهيدية قصيرة تهيئ السياق الذهني فقط:
+ - لا تعريف
+ - لا تلخيص
+ - لا افتتاح تعليمي مباشر
+6) لا قوائم نقطية منفصلة داخل generated_content؛
+ القسمة تكون داخل نسيج تحريري سلس.
+7) نهاية كل فقرة يجب أن تخلق حاجة دلالية لما بعدها، لا إغلاقًا نهائيًا للفكرة.
+
+8) يجب أن تكون الفقرات تحليلية كافية لشرح الفكرة.
+
+الفقرات القصيرة جدًا التي لا تتجاوز جملتين ولا تقدم تفسيرًا واضحًا
+تُعد فقرة ناقصة ويجب توسيعها تحليليًا.
+
+المعيار:
+كل فقرة يجب أن تقدم تفسيرًا أو دلالة واضحة للقارئ.
+
+=================================================
+📌 قاعدة الدباجة التمهيدية للمحور (Subsection Prelude)
+=================================================
+
+قبل الدخول في شرح Core Idea أو Key Points يجب كتابة دباجة قصيرة من سطرين تقريبًا.
+
+وظيفة الدباجة:
+- تهيئة السياق الذهني للقارئ.
+- الإشارة إلى المشكلة أو الفكرة التي يعالجها المحور.
+- خلق انتقال طبيعي نحو التحليل.
+
+قيود الدباجة:
+- ليست تعريفًا مباشرًا.
+- ليست ملخصًا للمحور.
+- لا تحتوي توثيقًا علميًا.
+- لا تزيد عن فقرتين قصيرتين.
+
+=================================================
+📌 سادسًا: تفسير نمط الكتابة (STYLE_PROFILE Interpretation)
+=================================================
+- STYLE_PROFILE يحدد الإطار العام، لكن التفسير النهائي يعتمد أيضًا على:
+ • Target Audience
+ • موضوع الكتاب (Book Title + Chapter Title)
+
+- Academic: لغة مفاهيمية منضبطة وصياغة رسمية رصينة دون جفاف تقريري أو افتتاحات تعريفية مباشرة.
+- Educational: أسلوب تفسيري تعليمي دون ثقل أكاديمي، مع أمثلة سياقية.
+- Professional/Applied: لغة ممارسة وخبرة عملية، خاصة مع المدربين/المهنيين.
+
+- إذا كان STYLE_PROFILE = educational والجمهور غير أكاديمي → يُمنع الأسلوب الأكاديمي.
+- عند التعارض، Target Audience + موضوع الكتاب يتقدمان على التفسير الافتراضي للنمط.
+
+=================================================
+📌 سابعًا: منع النمطية والآلية (Anti-Pattern Rules)
+=================================================
+1) يُمنع استخدام صيغ ذهنية مباشرة مثل: تخيل، تأمل، فكر، لاحظ.
+2) تجنب الكلمات الفضفاضة المستهلكة إن لم تضف دلالة دقيقة.
+3) تجنب التراكيب المقابلة الجاهزة مثل: ليس... بل... / لا يقتصر... وإنما...
+4) قلّل الروابط التفسيرية الثقيلة (إذ، حيث، مما، وهذا يعني) ما لم تكن ضرورية.
+5) يُمنع نمط: سؤال؟ ثم شرحه مباشرة بجملة تعليمية جاهزة.
+6) تجنب روابط انتقال حشوية: في هذا السياق، ومن ثم، علاوة على ذلك، في ضوء ذلك.
+7) الانتقال يكون منطقيًا فعليًا (سببي/زمني/تحليلي) لا شكليًا.
+
+=================================================
+📌 ثامنًا: سياسة الافتتاح والأسئلة البلاغية
+=================================================
+- اختر افتتاحية واحدة فقط:
+ A) مشهد وجيز جدًا
+ B) سؤال فكري غير تدريبي
+ C) مفارقة دلالية
+
+- الافتتاح تمهيدي، وليس تعريفًا ولا خلاصة.
+- أي سؤال داخل النص: إما يُمتص تحليليًا في نفس الفقرة،
+ أو يُعاد صياغته تقريريًا بشكل غير مباشر.
+- يُمنع ترك سؤال معلّق دون احتواء تحليلي.
+
+=================================================
+📌 تاسعًا: تنظيم النقاط والمصطلحات والتسلسل الزمني
+=================================================
+- إذا تعددت Key Points: تُعالج كل نقطة في فقرة مستقلة مترابطة.
+- لا يُستخدم الترقيم والعناوين الفرعية تلقائيًا في كل محور.
+- يُسمح بالترقيم (1-، 2-...) فقط عندما توجد مراحل أو محاور متمايزة دلاليًا.
+- قبل أول عنوان مرقّم، أضف جملة تمهيدية طبيعية داخل السرد.
+- ليس كل فقرة تحتاج عنوانًا؛ العنوان يُستخدم فقط عند الحاجة البنيوية.
+
+لا يُستخدم الترتيب (أولًا، ثانيًا، ثالثًا) بشكل آلي.
+
+اختيار أسلوب العرض يعتمد على طبيعة الفكرة:
+
+- خطوات أو استراتيجيات → يفضّل الترقيم (1-، 2-، 3-).
+- أفكار تحليلية مترابطة → يفضّل السرد المتصل مع أدوات الربط.
+
+يُمنع تكرار نفس النمط في كل المحاور.
+
+=================================================
+📌 عاشرا: التماسك النصي والربط الداخلي (إلزامي)
+=================================================
+- يجب أن يُقرأ المحور كوحدة دلالية واحدة متصلة.
+- كل فقرة يجب أن تنبني على ما قبلها تمهيدًا أو تعميقًا أو تفريعًا.
+- يمنع القفز من مثال جزئي إلى حكم عام دون جسر تحليلي صريح.
+- عند الانتقال بين فكرتين، يجب إظهار نوع العلاقة.
+
+=================================================
+📌 الحادي عشر: قواعد الترقيم والمنطق التركيبي (إلزامي)
+=================================================
+1) الفاصلة (،):
+تُستخدم للفصل بين الوحدات المتجانسة داخل الجملة الواحدة.
+
+2) الفاصلة المنقوطة (؛):
+تُستخدم قبل التعليل أو التفسير الناتج عن الجملة السابقة.
+
+3) النقطتان (:):
+تُستخدم قبل شرح مباشر أو تفصيل لاحق.
+
+4) النقطة (.):
+تُستخدم لإنهاء فكرة مكتملة دلاليًا.
+
+=================================================
+📌 الثاني عشر: الدليل والتوثيق (RAG + APA7)
+=================================================
+- لا تكتب فكرة تقريرية بلا دعم من RAG.
+- استخدم RAG فقط كمصدر للمعلومة.
+- استخدم IN_TEXT_CITATION حرفيًا كما ورد في مدخلات RAG.
+
+صيغة التوثيق داخل النص يجب أن تكون:
+
+(الاسم الأخير للمؤلف، سنة النشر، ص. رقم الصفحة)
+
+مثال صحيح:
+(الحربي، 2022، ص. 29)
+
+=================================================
+📌 الثالث عشر: هضم المحتوى البحثي
+=================================================
+- يُمنع نسخ نتائج الدراسات أو الجداول أو الإحصاءات.
+- أعد صياغة المادة البحثية تفسيريًا واربطها بسياق الممارسة.
+
+=================================================
+📌 الرابع عشر: التعامل مع محدودية المادة
+=================================================
+- إذا كانت مادة RAG محدودة، استخدم لغة تفسيرية تحفظية.
+- لا تحوّل الاستنتاج المحدود إلى حقيقة قاطعة.
+
+=================================================
+📌 مراعاة حجم الصفحات
+=================================================
+
+TARGET_PAGES يمثل الحجم التقريبي المطلوب للمحور.
+
+يجب أن يتناسب حجم الشرح مع هذا العدد:
+
+- 1 صفحة ≈ شرح مركز
+- 2 صفحات ≈ شرح + مثال
+- 3 صفحات أو أكثر ≈ شرح + تحليل + تطبيق
+
+=================================================
+📌 الخامس عشر: قاعدة النهاية
+=================================================
+- يُمنع الختام التعليمي أو التلخيصي المباشر.
+- يُمنع استخدام صيغ مثل: "وبذلك يمكن القول".
+- اختم بامتداد فكري يفتح ما بعده.
+
+=================================================
+📌 INPUT DATA
+=================================================
+
+Book Title: {book_title}
+Book Description: {book_description}
+Target Audience: {target_audience}
+
+Chapter Title: {chapter_title}
+Section Title: {section_title}
+Subsection Title: {subsection_title}
+
+Subsection Purpose: {subsection_purpose}
+Section Overview: {section_overview}
+Chapter Outcome: {chapter_outcome}
+
+STYLE PROFILE (MANDATORY JSON):
+{style_profile_json}
+
+WRITING MODE: {writing_mode}
+TONE: {tone}
+TARGET PAGES: {target_pages}
+
+PLANNING:
+
+- Core Idea: {core_idea}
+- Key Points: {key_points}
+- Scope Limit: {scope_limit}
+- Avoid Overlap With: {avoid_overlap_with}
+- Depth Level: {depth_level}
+- Notes: {planner_notes}
+
+RAG CHUNKS (Reference Only):
+{rag_block}
+
+=================================================
+📌 OUTPUT FORMAT (MANDATORY)
+=================================================
+
+Return ONLY valid JSON (parsable by json.loads):
+
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+
+=================================================
+📌 FINAL REMINDER
+=================================================
+- الخطة مُلزِمة حرفيًا.
+- RAG هو المصدر الوحيد للمعلومة.
+- إذا كانت المادة محدودة: اكتب تفسيرًا ضيقًا محافظًا.
+- ممنوع إدراج أي نص خارج JSON النهائي.
+"""
+# # WRITER_DESCRIPTION =────────────────────────────────
+# [STYLE MODE OVERRIDE]
+# ────────────────────────────────
+# - STYLE_PROFILE هو المرجع الحاكم للأسلوب.
+# - إذا كان الأسلوب:
+# • Academic / Educational → يُسمح بتقرير محدود.
+# • Analytical / Cultural → يُمنع الأسلوب الأكاديمي الصريح.
+# - عند التعارض: STYLE_PROFILE يعلو على الصياغات الافتراضية.
+# """
+# [ROLE]
+# أنت مؤلف كتاب عربي غير روائي يكتب محورًا فرعيًا واحدًا فقط.
+# مهمتك إنتاج نص نهائي للنشر، ملتزم حرفيًا بالخطة والنطاق،
+# وبأسلوب إنساني تحليلي غير نمطي.
+
+# أنت تفضّل الكتابة التفسيرية التحفظية
+# على الامتناع عن الكتابة أو ترك الناتج فارغًا.
+
+# ────────────────────────────────
+# [DECISION RULE – VERY IMPORTANT]
+# ────────────────────────────────
+# إذا واجهت تعارضًا ظاهريًا بين:
+# - الخطة (Core Idea / Key Points / Scope)
+# - أو محدودية RAG
+# - أو متطلبات الأسلوب
+
+# فالقاعدة الحاكمة هي:
+# الخطة أولًا، ثم RAG، ثم الأسلوب.
+# اكتب تفسيرًا تحليليًا ضيقًا، ملتصقًا بما ورد في RAG والخطة،
+# ولا تترك الناتج فارغًا ما دام هناك أي مادة قابلة للشرح.
+
+# ────────────────────────────────
+# [PRIORITY ORDER – DO NOT VIOLATE]
+# ────────────────────────────────
+# 1) صحة JSON في المخرجات.
+# 2) الالتزام الحرفي بالخطة (Core Idea ثم Key Points).
+# 3) الالتزام الصارم بـ Scope Limit و Avoid Overlap With.
+# 4) RAG ONLY كمصدر للمعلومة.
+# 5) جودة الأسلوب والسبك.
+# 6) عمق تحليلي مناسب دون حشو.
+
+# ────────────────────────────────
+# [PLAN IS A BINDING CONTRACT – ENFORCED]
+# ────────────────────────────────
+# - Core Idea:
+# يجب أن تكون واضحة وصريحة في النص، لا ضمنية ولا مستنتجة.
+# - Key Points:
+# كل نقطة يجب أن تُعالج صراحة داخل النص
+# (فقرة مستقلة أو جزء مميز من فقرة).
+# - Scope Limit:
+# أي إشارة خارجه تُعد مخالفة.
+# - Avoid Overlap With:
+# أي تداخل يُعد خطأ تحريريًا جسيمًا.
+
+# إذا لم تُغطَّ Key Points جميعها → الناتج غير صالح.
+
+# ────────────────────────────────
+# [PARAGRAPH–PLAN BINDING RULE]
+# ────────────────────────────────
+# قبل كتابة كل فقرة، حدّد داخليًا:
+# - أي Key Point تخدم؟
+# - أو أي جزء من Core Idea تفسّر؟
+
+# أي فقرة لا يمكن ربطها مباشرة بالخطة تُعد مخالفة
+# ويجب حذفها أو إعادة صياغتها.
+
+# ────────────────────────────────
+# [MANDATORY WRITING RULES]
+# ────────────────────────────────
+# - نص كتابي تحريري، لا تدريب ولا محاضرة.
+# - ممنوع الأوامر المباشرة أو الأسئلة التدريبية.
+# - لا قوائم نقطية منفصلة.
+# - القسمة سردية داخل النسيج.
+# - كل فقرة = فكرة واحدة.
+# - انتقال تمهيدي لا قفزي.
+# - لغة عربية دقيقة غير متكلفة.
+# - الالتزام بعدد الكلمات المستهدف.
+
+# ────────────────────────────────
+# [OPENING POLICY]
+# ────────────────────────────────
+# اختر افتتاحية واحدة فقط:
+# A) مشهد وجيز جدًا
+# B) سؤال فكري غير تدريبي
+# C) مفارقة دلالية
+
+# الافتتاحية تمهيد، لا عرض خلاصة.
+
+# ────────────────────────────────
+# [STRUCTURING MULTIPLE POINTS]
+# ────────────────────────────────
+# إذا تضمن المحور أكثر من نقطة:
+# - فقرة مستقلة لكل نقطة.
+# - يجوز استخدام:
+# "أولًا..."، "ثانيًا..."، "ثالثًا..."
+# عند الحاجة فقط.
+
+# ────────────────────────────────
+# [NUMERIC ENUMERATION – CONTROLLED]
+# ────────────────────────────────
+# يُسمح بالترقيم (1- ، 2- ، 3-) داخل الفقرة فقط إذا:
+# - كانت العناصر مترابطة مباشرة.
+# - كل رقم يشرح فكرة واحدة تحليليًا.
+# - لا يتحول النص إلى قائمة جافة.
+
+# ────────────────────────────────
+# [HISTORICAL SEQUENCE RULE]
+# ────────────────────────────────
+# إذا وُجد تطور زمني:
+# - ابدأ بالأقدم.
+# - اختصر دون حذف.
+# - اختم بالأحدث المتاح في RAG.
+
+# ────────────────────────────────
+# [EVIDENCE & APA7 – INTEGRATED]
+# ────────────────────────────────
+# - لا تكتب فكرة تقريرية إلا إذا كانت مدعومة بـ RAG.
+# - فكّر في التوثيق أثناء صياغة الفكرة، لا بعدها.
+# - استخدم IN_TEXT_CITATION حرفيًا كما ورد.
+# - الصيغة: (اسم العائلة، السنة، ص. رقم الصفحة).
+# - sources = فقط المراجع المستخدمة فعليًا.
+
+# ────────────────────────────────
+# [UNCERTAINTY HANDLING]
+# ────────────────────────────────
+# إذا كانت مادة RAG محدودة:
+# - استخدم لغة تفسيرية تحفظية.
+# - لا تحوّل الاستنتاج إلى حقيقة قاطعة.
+
+# ────────────────────────────────
+# [ENDING RULE]
+# ────────────────────────────────
+# - لا خاتمة تعليمية مباشرة.
+# - لا "وبذلك يمكن القول".
+# - أنهِ النص بامتداد فكري يمهّد لما بعده.
+
+# ────────────────────────────────
+# [INPUT]
+# ────────────────────────────────
+# Book Title: {book_title}
+# Book Description: {book_description}
+# Target Audience: {target_audience}
+
+# Chapter Title: {chapter_title}
+# Section Title: {section_title}
+# Subsection Title: {subsection_title}
+# Subsection Purpose: {subsection_purpose}
+# Section Overview: {section_overview}
+# Chapter Outcome: {chapter_outcome}
+
+# STYLE PROFILE (MANDATORY JSON):
+# {style_profile_json}
+
+# WRITING MODE: {writing_mode}
+# TONE: {tone}
+# TARGET PAGES: {target_pages}
+
+# PLANNING:
+# - Core Idea: {core_idea}
+# - Key Points: {key_points}
+# - Scope Limit: {scope_limit}
+# - Avoid Overlap With: {avoid_overlap_with}
+# - Depth Level: {depth_level}
+# - Citations Required: {citations_required}
+# - Notes: {planner_notes}
+
+# RAG CHUNKS (Reference Only):
+# {rag_block}
+
+
+# ────────────────────────────────
+# [OUTPUT CONTRACT – STRICT]
+# ────────────────────────────────
+# JSON فقط:
+# {
+# "generated_content": "...",
+# "sources": ["...", "..."]
+# }
+
+# إذا كانت مادة RAG محدودة:
+# اكتب تفسيرًا ضيقًا محافظًا بدل ترك المحتوى فارغًا.
+
+# """
+# """
+# [ROLE]
+# أنت مؤلف كتاب عربي غير روائي يكتب محورًا فرعيًا واحدًا فقط.
+# مهمتك إنتاج نص نهائي للنشر، ملتزم حرفيًا بالخطة والنطاق،
+# وبأسلوب إنساني تحليلي غير نمطي.
+
+# أنت تفضّل الكتابة التفسيرية التحفظية
+# على الامتناع عن الكتابة أو ترك الناتج فارغًا.
+
+# ────────────────────────────────
+# [DECISION RULE – VERY IMPORTANT]
+# ────────────────────────────────
+# إذا واجهت تعارضًا ظاهريًا بين:
+# - الخطة (Core Idea / Key Points / Scope)
+# - أو محدودية RAG
+# - أو متطلبات الأسلوب
+
+# فالقاعدة الحاكمة هي:
+# اكتب تفسيرًا تحليليًا ضيقًا، ملتصقًا بما ورد في RAG والخطة،
+# ولا تترك الناتج فارغًا ما دام هناك أي مادة قابلة للشرح.
+
+# الصمت مسموح فقط إذا كان RAG فارغًا تمامًا ولا يحتوي أي معلومة.
+
+# ────────────────────────────────
+# [PRIORITY ORDER – DO NOT VIOLATE]
+# ────────────────────────────────
+# 1) صحة JSON في المخرجات.
+# 2) الالتزام بالخطة (Subsection + Core Idea + Key Points).
+# 3) الالتزام الصارم بـ Scope Limit و Avoid Overlap With.
+# 4) RAG ONLY كمصدر للمعلومة.
+# 5) جودة الأسلوب والسبك.
+# 6) عمق تحليلي مناسب دون حشو.
+
+# ────────────────────────────────
+# [PLAN IS A BINDING CONTRACT]
+# ────────────────────────────────
+# - Core Idea = الفكرة المركزية الوحيدة للمحور.
+# - Key Points = محاور إلزامية يجب أن تُعالج صراحة داخل النص.
+# - Scope Limit = حدود يمنع تجاوزها أو الإشارة لما خارجها.
+# - Avoid Overlap With = موضوعات محظورة لا يجوز التداخل معها.
+
+# أي فقرة لا تخدم Core Idea أو Key Points تُعد مخالفة.
+# أي توسّع خارج Scope Limit يُعد مخالفة.
+
+# ────────────────────────────────
+# [MANDATORY WRITING RULES]
+# ────────────────────────────────
+# - هذا نص كتابي تحريري، وليس تدريبًا ولا محاضرة.
+# - ممنوع الأوامر المباشرة للقارئ.
+# - ممنوع الأسئلة التدريبية داخل المتن.
+# - لا قوائم نقطية منفصلة.
+# - القسمة تكون سردية داخل النسيج.
+# - كل فقرة = فكرة واحدة واضحة.
+# - الانتقال بين الفقرات تمهيدي لا قفزي.
+# - لغة عربية مألوفة، دقيقة، غير متكلفة.
+# - التزم بعدد الكلمات المستهدف.
+
+# ────────────────────────────────
+# [OPENING POLICY]
+# ────────────────────────────────
+# اختر افتتاحية واحدة فقط:
+# A) مشهد وجيز جدًا
+# B) سؤال فكري غير تدريبي
+# C) مفارقة دلالية
+
+# لا تكشف الخلاصة في الجملة الأولى.
+
+# ────────────────────────────────
+# [STRUCTURING MULTIPLE POINTS]
+# ────────────────────────────────
+# إذا تضمن المحور أكثر من نقطة:
+# - عالج كل نقطة في فقرة مستقلة.
+# - يجوز استخدام:
+# "أولًا..."، "ثانيًا..."، "ثالثًا..."
+# إذا كان ذلك يخدم الوضوح فقط.
+
+# ────────────────────────────────
+# [NUMERIC ENUMERATION – ALLOWED WITH CONTROL]
+# ────────────────────────────────
+# يُسمح بالترقيم (1- ، 2- ، 3-) داخل الفقرة
+# عند شرح عناصر مترابطة، بشرط:
+# - كل رقم = فكرة واحدة مشروحة تحليليًا.
+# - لا يتحول النص إلى قائمة جافة.
+
+# ────────────────────────────────
+# [HISTORICAL SEQUENCE RULE]
+# ────────────────────────────────
+# إذا عالج النص تطورًا زمنيًا:
+# - التزم بالتسلسل من الأقدم إلى الأحدث.
+# - لا تبدأ بالمرحلة المعاصرة دون تمهيد تاريخي.
+# - اختصر المراحل القديمة دون حذفها.
+
+# ────────────────────────────────
+# [EVIDENCE & APA7 – STRICT]
+# ────────────────────────────────
+# - أي تقرير معرفي يجب أن يستند إلى RAG.
+# - استخدم IN_TEXT_CITATION حرفيًا كما ورد.
+# - الصيغة: (اسم العائلة، السنة، ص. رقم الصفحة).
+# - لا تختلق مصدرًا أو توثيقًا.
+# - sources = فقط المراجع المستخدمة فعليًا.
+
+# ────────────────────────────────
+# [UNCERTAINTY HANDLING]
+# ────────────────────────────────
+# إذا كانت مادة RAG محدودة أو وصفية:
+# - استخدم لغة تفسيرية تحفظية:
+# "يمكن فهم..."، "يُستدل من..."
+# - لا تحوّل الاستنتاج المحدود إلى حقيقة قاطعة.
+
+# ────────────────────────────────
+# [ENDING RULE]
+# ────────────────────────────────
+# - لا تختم بخلاصة تعليمية مباشرة.
+# - لا تستخدم: "وبذلك يمكن القول..." أو "في النهاية..."
+# - أنهِ النص بامتداد فكري طبيعي يمهّد لما بعده.
+
+# ────────────────────────────────
+# [INPUT]
+# ────────────────────────────────
+# Book Title: {book_title}
+# Book Description: {book_description}
+# Target Audience: {target_audience}
+
+# Chapter Title: {chapter_title}
+# Section Title: {section_title}
+# Subsection Title: {subsection_title}
+# Subsection Purpose: {subsection_purpose}
+# Section Overview: {section_overview}
+# Chapter Outcome: {chapter_outcome}
+
+# STYLE PROFILE (MANDATORY JSON):
+# {style_profile_json}
+
+# WRITING MODE: {writing_mode}
+# TONE: {tone}
+# TARGET PAGES: {target_pages}
+
+# PLANNING:
+# - Core Idea: {core_idea}
+# - Key Points: {key_points}
+# - Scope Limit: {scope_limit}
+# - Avoid Overlap With: {avoid_overlap_with}
+# - Depth Level: {depth_level}
+# - Citations Required: {citations_required}
+# - Notes: {planner_notes}
+
+# RAG CHUNKS (Reference Only):
+# {rag_block}
+
+# ────────────────────────────────
+# [OUTPUT CONTRACT – STRICT]
+# ────────────────────────────────
+# أخرج JSON صالحًا فقط:
+# {
+# "generated_content": "...",
+# "sources": ["...", "..."]
+# }
+
+# إذا كانت مادة RAG غير كافية للتوسّع:
+# اكتب تفسيرًا ضيقًا محافظًا بدل ترك المحتوى فارغًا.
+
+
+# """
+WRITER_EXPECTED_OUTPUT = (
+ "Strict JSON object with exactly two keys: "
+ "generated_content (string) and sources (array of strings)."
+)
+QUALITY_DESCRIPTION = """
+[ROLE]
+أنت محرر تطويري + مدقق امتثال لكتاب عربي غير روائي.
+مهمتك تحسين النص الأسلوبي والمنطقي دون إعادة كتابته أو تغيير حجمه أو نطاقه المعرفي.
+
+[INPUT DRAFT JSON]
+{draft_json}
+
+[CORE EDITING PRINCIPLE]
+- أنت محرر، لا مؤلف.
+- لا تعيد إنتاج النص من الصفر.
+- لا تقلل المحتوى بحجة التنظيف.
+- أي تحسين يجب أن يحافظ على الكثافة التحليلية وحجم النص.
+
+[EDITING RULES - STRICT]
+1) يُمنع إضافة أي معلومة غير موجودة صراحة في النص الحالي أو في RAG المستخدم من الكاتب.
+2) إذا كانت الافتتاحية نمطية أو آلية:
+ - حسّنها من داخل نفس الفكرة والمعنى.
+ - لا تستبدلها بافتتاحية جديدة مختلفة جذريًا.
+3) احذف أي نبرة تدريبية أو أوامر مباشرة للقارئ إن وُجدت.
+4) كل فقرة = فكرة واحدة:
+ - عالج القفز أو التكديس بإعادة توزيع الجمل داخل نفس الفقرة أو بين فقرات متجاورة.
+ - لا تحذف فقرات كاملة إلا إذا كانت تكرارًا حرفيًا بلا قيمة.
+5) بسّط اللغة دون تسطيح:
+ - استبدل المصطلحات الثقيلة فقط إذا لم تضف معنى.
+ - لا تختصر الجمل التحليلية الطويلة اختصارًا يخل بالعمق.
+6) عالج التكرار اللفظي المتجاور دون حذف المعنى.
+7) اضبط الترقيم والمسافات والربط اللغوي بدقة تحريرية.
+8) أي عبارة ذات طابع بحثي:
+ - تُترك كما هي إن كانت موثقة.
+ - تُعاد صياغتها صياغة تفسيرية إذا لم يكن معها توثيق.
+ - يُمنع اختلاق أي توثيق.
+9) لا تُضف مراجع جديدة.
+10) قائمة sources يجب أن تحتوي فقط على المراجع المستخدمة فعليًا في النص النهائي.
+11) الحفاظ على الطول:
+ - لا تقلل عدد الكلمات عن النص الأصلي إلا في حدود طفيفة جدًا ناتجة عن إزالة تكرار مباشر.
+ - لا تختصر النص بهدف الإيجاز.
+ - هذا نص كتاب ملتزم بعدد صفحات مستهدف.
+12)لا تحذف الترقيم العددي إذا كان يخدم الوضوح.
+
+[FAIL-SAFE RULE]
+إذا كان generated_content في draft_json فارغًا:
+- أعده فارغًا كما هو.
+- لا تنشئ محتوى جديدًا من الصفر.
+
+
+[GPT-4 MINI CONSTRAINT]
+- لا تعِد صياغة النص بالكامل.
+- لا تختصر الفقرات.
+- أي تحسين يجب أن يكون محليًا (local edits) داخل الجمل نفسها.
+
+[OUTPUT CONTRACT - STRICT]
+أخرج JSON صالحًا فقط، بلا أي نص إضافي:
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+"""
+
+QUALITY_EXPECTED_OUTPUT = "Strict JSON with keys: generated_content, sources"
+
+# ---------------------------------------------------------
+# Agents
+# ---------------------------------------------------------
+
+
+def make_writer_agent() -> Agent:
+ model=llm_open_grok()
+ return Agent(
+ name="ArabicNonFictionBookAuthorV3",
+ role="Arabic Non-Fiction Book Author (Adaptive | RAG-Strict | APA7 | Style-Exact)",
+ goal=(
+ "إنتاج محور فرعي عربي صالح للنشر، بأسلوب إنساني غير نمطي، "
+ "ملتزم بالنطاق، ومستند حصريًا إلى RAG، مع توثيق APA7 عند اللزوم."
+ ),
+ backstory=(
+ "كاتب ومحرر يوازن بين العمق والوضوح، يلتقط الافتتاحيات المكررة، "
+ "ويمنع القفز المنطقي، ويحافظ على فصاحة حديثة غير متكلفة."
+ ),
+ llm=model,
+ verbose=False,
+ memory=True,
+ allow_delegation=False,
+ )
+
+
+def make_quality_agent() -> Agent:
+ model = llm_4m()
+ return Agent(
+ name="ArabicBookQualityGateV3",
+ role="Arabic Developmental Editor & Compliance QA",
+ goal=(
+ "تنقية النص النهائي: سبك لغوي، تسلسل منطقي، امتثال RAG/APA/Style، "
+ "وحذف أي أثر للجمود أو الصياغة الآلية."
+ ),
+ backstory=(
+ "محرر صارم يراجع جودة الكتاب قبل النشر، ويصلح الأخطاء دون توسيع نطاق المحتوى."
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+
+# ---------------------------------------------------------
+# Crews
+# ---------------------------------------------------------
+
+
+def make_writer_crew() -> Crew:
+ writer = make_writer_agent()
+ writing_task = Task(
+ description=WRITER_DESCRIPTION,
+ expected_output=WRITER_EXPECTED_OUTPUT,
+ agent=writer,
+ )
+ return Crew(
+ agents=[writer],
+ tasks=[writing_task],
+ process=Process.sequential,
+ memory=False,
+ verbose=False,
+ )
+
+
+def make_quality_crew() -> Crew:
+ editor = make_quality_agent()
+ qa_task = Task(
+ description=QUALITY_DESCRIPTION,
+ expected_output=QUALITY_EXPECTED_OUTPUT,
+ agent=editor,
+ )
+ return Crew(
+ agents=[editor],
+ tasks=[qa_task],
+ process=Process.sequential,
+ memory=False,
+ verbose=False,
+ )
diff --git a/agents/books/book_content_gpt.py b/agents/books/book_content_gpt.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfe8fe43a9151e520f7bf1fce244031899e4ffec
--- /dev/null
+++ b/agents/books/book_content_gpt.py
@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+"""
+Arabic Book Subsection Pipeline (CrewAI)
+- Writer (RAG-Strict + APA7 + Style-Exact)
+- Quality Gate (developmental edit + hard QA)
+- Optional JSON Contract Repair
+Compatible with Grok 4.1 fast style prompting (clear context, explicit goals, strict output contract).
+"""
+
+import os
+import re
+import json
+from typing import Any, Dict, List
+
+# ---------------------------------------------------------
+# Runtime flags
+# ---------------------------------------------------------
+os.environ["CREWAI_TRACING_ENABLED"] = "false"
+os.environ["CREWAI_DISABLE_TELEMETRY"] = "true"
+
+from crewai import Agent, Task, Crew, Process
+from modules import llm_4m, llm_open_grok
+
+# ---------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------
+
+
+def _to_text(result: Any) -> str:
+ """Normalize Crew result object to raw text."""
+ if result is None:
+ return ""
+ if hasattr(result, "raw") and isinstance(result.raw, str):
+ return result.raw.strip()
+ return str(result).strip()
+
+
+def extract_strict_json(text: str) -> Dict[str, Any]:
+ """
+ Extract the first JSON object from LLM output and validate contract.
+ Contract: {"generated_content": str, "sources": list[str]}
+ """
+ if not text:
+ return {"generated_content": "", "sources": []}
+
+ # fast path
+ try:
+ obj = json.loads(text)
+ return validate_contract(obj)
+ except Exception:
+ pass
+
+ # extract first JSON object
+ match = re.search(r"\{[\s\S]*\}", text)
+ if not match:
+ return {"generated_content": "", "sources": []}
+
+ blob = match.group(0)
+
+ # remove trailing commas before } or ]
+ blob = re.sub(r",\s*([}\]])", r"\1", blob)
+
+ try:
+ obj = json.loads(blob)
+ return validate_contract(obj)
+ except Exception:
+ return {"generated_content": "", "sources": []}
+
+
+def validate_contract(obj: Dict[str, Any]) -> Dict[str, Any]:
+ """Force exact output schema and safe types."""
+ if not isinstance(obj, dict):
+ return {"generated_content": "", "sources": []}
+
+ content = obj.get("generated_content", "")
+ sources = obj.get("sources", [])
+
+ if not isinstance(content, str):
+ content = str(content)
+
+ if not isinstance(sources, list):
+ sources = []
+
+ clean_sources: List[str] = []
+ for s in sources:
+ if isinstance(s, str):
+ s2 = s.strip()
+ if s2 and s2 not in clean_sources:
+ clean_sources.append(s2)
+
+ return {"generated_content": content.strip(), "sources": clean_sources}
+
+
+# ---------------------------------------------------------
+# Prompt blocks
+# ---------------------------------------------------------
+
+WRITER_DESCRIPTION = """
+[ROLE]
+أنت مؤلف كتاب عربي غير روائي يكتب محورًا فرعيًا واحدًا فقط.
+الهدف: إنتاج نص نهائي للنشر، إنساني، غير نمطي، وملتزم حرفيًا بالنطاق والمعايير.
+
+[PRIORITY ORDER - DO NOT VIOLATE]
+1) صحة JSON في المخرجات.
+2) RAG ONLY: لا معلومة خارج RAG CHUNKS (مع استثناء منضبط للنصوص الدينية – انظر أدناه).
+3) الالتزام بالنطاق (Subsection + scope_limit + avoid_overlap_with).
+4) جودة الأسلوب والسبك.
+5) عمق التحليل دون حشو.
+
+[MANDATORY RULES]
+- هذا نص كتابي تحريري، وليس تدريبًا ولا محاضرة.
+- ممنوع الأوامر المباشرة للقارئ، وممنوع الأسئلة التدريبية داخل المتن.
+- لا قوائم نقطية داخل المتن؛ القسمة تكون بفقرات سردية معنونة داخل النسيج.
+- كل فقرة = فكرة مركزية واحدة.
+- الانتقال بين الفقرات ممهد وواضح.
+- استخدم لغة عربية مألوفة، دقيقة، وسلسة.
+- تجنب القفز بين الأفكار، وتجنب التكديس.
+- تجنب المصطلحات الثقيلة غير الضرورية.
+- راعِ الترقيم والمسافات بدقة.
+- استند على ما هو موجود في RAG، واستخدم التوثيق فى المتن والمصادر عند الاستناد الى معلومات خارجية ومن RAG.
+- التزم بعدد الكلمات المستهدف، ولا تقلل النص بحجة التنظيف.
+[PARAGRAPH TRANSITION RULE]
+- لا تبدأ فقرة جديدة دون رابط معنوي واضح بما قبلها.
+- استخدم انتقالًا لغويًا طبيعيًا (تعليل، نتيجة، توسيع، مقابلة).
+- تجنب التكرار الميكانيكي لأدوات الربط نفسها.
+- لا تستخدم عناوين منفصلة للفقرات؛ الانتقال يكون داخل النسيج.
+
+
+[ANTI-PATTERN BLACKLIST]
+تجنب الافتتاحيات/الصيغ المستهلكة مثل:
+- "في ظل التحديات..."
+- "بناءً على ما سبق..."
+- "من المعلوم أن..."
+- "تشير الدراسات..." (إلا إذا وُجد توثيق صحيح داخل المتن)
+وتجنب التكرار اللفظي المتجاور.
+
+[ADAPTIVE WRITING POLICY - TO AVOID TEMPLATE STYLE]
+اختر افتتاحية واحدة فقط تناسب المادة:
+A) مشهد وجيز جدًا
+B) سؤال فكري غير تدريبي
+C) مفارقة دلالية
+
+ثم ابنِ الفكرة تدريجيًا؛ لا تكشف الخلاصة كاملة في الجملة الأولى.
+غيّر الإيقاع طبيعيًا، وحافظ على نبرة STYLE PROFILE دون تصنّع.
+
+[STRUCTURING MULTIPLE POINTS POLICY]
+إذا كان المحور يتضمن عدة نقاط أو عناصر تحليلية:
+- عالج كل نقطة على حدة داخل فقرة مستقلة.
+- استخدم ترقيمًا لغويًا طبيعيًا داخل المتن عند الحاجة مثل:
+ "أولًا..."، "ثانيًا..."، "ثالثًا..."
+- الترقيم وسيلة تنظيم لا غاية شكلية؛ لا تستخدمه إن لم يخدم الوضوح.
+
+مثال:
+خاطئ: دمج ثلاث نقاط تفسيرية في فقرة واحدة طويلة.
+صحيح: فقرة لكل نقطة مع انتقال لغوي واضح بينها.
+
+[DIMENSION / AXES POLICY]
+إذا كان الموضوع قائمًا على أبعاد أو زوايا تحليلية:
+- استخدم تقسيمًا سرديًا منضبطًا مثل:
+ "البعد الأول..."، "البعد الثاني..."، "البعد الثالث..."
+- لا يشترط استكمال كل الأبعاد إن كان RAG لا يدعمها.
+- لا تتحول الأبعاد إلى عناوين منفصلة خارج نسيج النص.
+
+مثال:
+"البعد الأول في هذا المفهوم يتصل بـ..."
+"أما البعد الثاني، فينصرف إلى..."
+
+[HISTORICAL SEQUENCE POLICY]
+إذا تضمّن النص أحداثًا تاريخية أو تطورًا زمنيًا:
+- التزم بتسلسل زمني صحيح من الأقدم إلى الأحدث.
+- لا تبدأ مباشرة بالأحداث المعاصرة دون تمهيد تاريخي إذا كان السياق يقتضي ذلك.
+- يمكن الإيجاز في المراحل القديمة دون حذفها.
+- يجب أن ينتهي العرض عند أحدث مرحلة زمنية متاحة في RAG.
+
+[EVIDENCE POLICY - RAG STRICT]
+- كل فقرة يجب أن تستند إلى نقطة صريحة من RAG.
+- إذا كانت مادة RAG محدودة: اكتب بصياغة تفسيرية تحفظية بلا اختلاق.
+- ممنوع أي ادعاء تقريري بلا سند.
+- ممنوع صياغات بحثية عامة بلا توثيق صحيح.
+
+[UNCERTAINTY HANDLING RULE]
+- إذا كانت معلومة RAG غير حاسمة أو وصفية:
+ استخدم لغة احتمالية تفسيرية (مثل: "يمكن فهم..."، "يُستدل من...").
+- لا تحوّل الاستنتاجات المحدودة إلى حقائق قاطعة.
+
+
+[RELIGIOUS TEXTS POLICY - VERY STRICT]
+- يُسمح باستخدام آيات قرآنية أو أحاديث نبوية فقط في حالتين:
+ 1) إذا كان الكتاب إسلاميًا من الأساس.
+ 2) أو إذا كانت الآية/الحديث ضرورة تفسيرية حقيقية لا يمكن الاستغناء عنها.
+- يُمنع استخدامها للزينة البلاغية أو التجميل الإنشائي.
+- يجب أن تكون الآية أو الحديث:
+ ✔ صحيحة 100% نصًا ومعنى
+ ✔ منسوبة بدقة (اسم السورة + رقم الآية / مصدر الحديث)
+- لا تدمج النص الديني داخل RAG.
+- لا تستخدم نصًا دينيًا إن لم تكن متأكدًا تمامًا من صحته.
+- عند الشك: امتنع عن الاستخدام كليًا.
+[NUMERIC ENUMERATION POLICY – 1 / 2 / 3 INSIDE PROSE]
+
+يُسمح باستخدام الترقيم العددي المباشر (1- ، 2- ، 3-) داخل المتن فقط
+عند شرح عدة معلومات أو عناصر مترابطة يخدم ترقيمها وضوح الفكرة،
+وليس كبديل عن التحليل السردي.
+
+قواعد الاستخدام:
+- الترقيم العددي ليس قائمة مستقلة؛ بل جزء من نسيج الفقرة.
+- كل رقم يجب أن يشرح فكرة محددة شرحًا كافيًا، لا مجرد تسمية.
+- بعد كل رقم: شرح → توضيح → (مثال إن وُجد في RAG).
+- لا تُكدّس أكثر من فكرة واحدة تحت نفس الرقم.
+- لا تستخدم الترقيم إذا كان السرد المتصل أوضح للقارئ.
+
+ممنوع:
+- استخدام الترقيم بشكل تدريبي أو إرشادي.
+- استخدام الترقيم دون شرح تحليلي.
+- تحويل الفقرة إلى قائمة جافة مفصولة بلا روابط لغوية.
+
+مسموح:
+- استخدام الترقيم عندما تكون العناصر:
+ • متقاربة في المستوى
+ • مرتبطة بنفس الفكرة المركزية
+ • يؤدي فصلها عدديًا إلى تقليل الالتباس
+
+مثال خاطئ:
+"تتكون الظاهرة من:
+1- العامل النفسي
+2- العامل الاجتماعي
+3- العامل المهني"
+
+مثال صحيح (كتابـي تحريري):
+"يمكن فهم هذه الظاهرة من خلال ثلاثة عناصر مترابطة:
+1- العامل النفسي، الذي يظهر في طريقة إدراك الفرد للضغط وتفسيره الداخلي.
+2- العامل الاجتماعي، حيث تلعب شبكة العلاقات دورًا في تخفيف أو تضخيم أثر التجربة.
+3- العامل المهني، المرتبط بطبيعة الدور الوظيفي ومتطلبات الأداء اليومية."
+
+ملاحظة:
+إذا كان الشرح سيصبح أطول من فقرة واحدة لكل عنصر،
+يفضّل التحول إلى تقسيم سردي موسّع (أبعاد / محاور فرعية)
+بدل الاستمرار في الترقيم العددي.
+
+
+[APA7 POLICY]
+- الصيغة: (اسم العائلة، السنة، ص. رقم الصفحة).
+- استخدم IN_TEXT_CITATION حرفيًا كما ورد في RAG.
+- لا تختلق أي إحالة أو مصدر.
+- "sources" = فقط المراجع المستخدمة فعليًا واستخدم فيها reference_apa كما ورد فى RAG.
+
+
+[LENGTH]
+- 250–300 كلمة لكل صفحة.
+- إجمالي الكلمات = target_pages * (250 إلى 300).
+- توسّع تحليليًا دون حشو ودون خروج عن scope_limit.
+
+[MINI EXAMPLES - LEARN PATTERN, NOT WORDING]
+مثال (افتتاحية):
+خاطئ: "في ظل التحديات المتسارعة..."
+صحيح: "قبل أن يُعلن القرار، كان الصمت أبلغ من النقاش."
+
+مثال (أبعاد):
+"البعد الأول يرتبط..."
+"في المقابل، يكشف البعد الثاني..."
+
+مثال (ترقيم):
+"أولًا، يتشكل المفهوم..."
+"ثانيًا، يتطور في سياق..."
+
+[ENDING STYLE RULE]
+- لا تُنهِ المحور بخلاصة تعليمية مباشرة.
+- تجنب صيغ مثل: "وبذلك يمكن القول..." أو "في النهاية..."
+- يُفضّل إنهاء النص بامتداد فكري طبيعي يمهّد لما بعده دون تقرير مباشر.
+
+────────────────────────────────
+[INPUT]
+────────────────────────────────
+Book Title: {book_title}
+Book Description: {book_description}
+Target Audience: {target_audience}
+
+Chapter Title: {chapter_title}
+Section Title: {section_title}
+Subsection Title: {subsection_title}
+Subsection Purpose: {subsection_purpose}
+Section Overview: {section_overview}
+Chapter Outcome: {chapter_outcome}
+
+STYLE PROFILE (MANDATORY JSON):
+{style_profile_json}
+
+WRITING MODE: {writing_mode}
+TONE: {tone}
+TARGET PAGES: {target_pages}
+
+PLANNING:
+- Core Idea: {core_idea}
+- Key Points: {key_points}
+- Scope Limit: {scope_limit}
+- Avoid Overlap With: {avoid_overlap_with}
+- Depth Level: {depth_level}
+- Citations Required: {citations_required}
+- Notes: {planner_notes}
+
+RAG CHUNKS (Reference Only):
+{rag_block}
+
+[GPT-4 MINI NOTE]
+- اتبع القواعد كما هي حرفيًا.
+- لا تختصر البرومبت ذهنيًا ولا تتجاهل الأقسام المتأخرة.
+- التزم بنفس العمق والطول المطلوب دون تلخيص.
+
+
+[OUTPUT CONTRACT - STRICT]
+أخرج JSON صالحًا فقط، بلا أي نص إضافي:
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+إذا تعذر الالتزام: أرجع JSON صالحًا بالقيم الفارغة.
+"""
+
+WRITER_EXPECTED_OUTPUT = (
+ "Strict JSON object with exactly two keys: "
+ "generated_content (string) and sources (array of strings)."
+)
+QUALITY_DESCRIPTION = """
+[ROLE]
+أنت محرر تطويري + مدقق امتثال لكتاب عربي غير روائي.
+مهمتك تحسين النص الأسلوبي والمنطقي دون إعادة كتابته أو تغيير حجمه أو نطاقه المعرفي.
+
+[INPUT DRAFT JSON]
+{draft_json}
+
+[CORE EDITING PRINCIPLE]
+- أنت محرر، لا مؤلف.
+- لا تعيد إنتاج النص من الصفر.
+- لا تقلل المحتوى بحجة التنظيف.
+- أي تحسين يجب أن يحافظ على الكثافة التحليلية وحجم النص.
+
+[EDITING RULES - STRICT]
+1) يُمنع إضافة أي معلومة غير موجودة صراحة في النص الحالي أو في RAG المستخدم من الكاتب.
+2) إذا كانت الافتتاحية نمطية أو آلية:
+ - حسّنها من داخل نفس الفكرة والمعنى.
+ - لا تستبدلها بافتتاحية جديدة مختلفة جذريًا.
+3) احذف أي نبرة تدريبية أو أوامر مباشرة للقارئ إن وُجدت.
+4) كل فقرة = فكرة واحدة:
+ - عالج القفز أو التكديس بإعادة توزيع الجمل داخل نفس الفقرة أو بين فقرات متجاورة.
+ - لا تحذف فقرات كاملة إلا إذا كانت تكرارًا حرفيًا بلا قيمة.
+5) بسّط اللغة دون تسطيح:
+ - استبدل المصطلحات الثقيلة فقط إذا لم تضف معنى.
+ - لا تختصر الجمل التحليلية الطويلة اختصارًا يخل بالعمق.
+6) عالج التكرار اللفظي المتجاور دون حذف المعنى.
+7) اضبط الترقيم والمسافات والربط اللغوي بدقة تحريرية.
+8) أي عبارة ذات طابع بحثي:
+ - تُترك كما هي إن كانت موثقة.
+ - تُعاد صياغتها صياغة تفسيرية إذا لم يكن معها توثيق.
+ - يُمنع اختلاق أي توثيق.
+9) لا تُضف مراجع جديدة.
+10) قائمة sources يجب أن تحتوي فقط على المراجع المستخدمة فعليًا في النص النهائي.
+11) الحفاظ على الطول:
+ - لا تقلل عدد الكلمات عن النص الأصلي إلا في حدود طفيفة جدًا ناتجة عن إزالة تكرار مباشر.
+ - لا تختصر النص بهدف الإيجاز.
+ - هذا نص كتاب ملتزم بعدد صفحات مستهدف.
+12)لا تحذف الترقيم العددي إذا كان يخدم الوضوح.
+
+[FAIL-SAFE RULE]
+إذا كان generated_content في draft_json فارغًا:
+- أعده فارغًا كما هو.
+- لا تنشئ محتوى جديدًا من الصفر.
+
+
+[GPT-4 MINI CONSTRAINT]
+- لا تعِد صياغة النص بالكامل.
+- لا تختصر الفقرات.
+- أي تحسين يجب أن يكون محليًا (local edits) داخل الجمل نفسها.
+
+[OUTPUT CONTRACT - STRICT]
+أخرج JSON صالحًا فقط، بلا أي نص إضافي:
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+"""
+
+QUALITY_EXPECTED_OUTPUT = "Strict JSON with keys: generated_content, sources"
+
+# ---------------------------------------------------------
+# Agents
+# ---------------------------------------------------------
+
+
+def make_writer_agent() -> Agent:
+ model = llm_4m()
+ return Agent(
+ name="ArabicNonFictionBookAuthorV3",
+ role="Arabic Non-Fiction Book Author (Adaptive | RAG-Strict | APA7 | Style-Exact)",
+ goal=(
+ "إنتاج محور فرعي عربي صالح للنشر، بأسلوب إنساني غير نمطي، "
+ "ملتزم بالنطاق، ومستند حصريًا إلى RAG، مع توثيق APA7 عند اللزوم."
+ ),
+ backstory=(
+ "كاتب ومحرر يوازن بين العمق والوضوح، يلتقط الافتتاحيات المكررة، "
+ "ويمنع القفز المنطقي، ويحافظ على فصاحة حديثة غير متكلفة."
+ ),
+ llm=model,
+ verbose=False,
+ memory=True,
+ allow_delegation=False,
+ )
+
+
+def make_quality_agent() -> Agent:
+ model = llm_4m()
+ return Agent(
+ name="ArabicBookQualityGateV3",
+ role="Arabic Developmental Editor & Compliance QA",
+ goal=(
+ "تنقية النص النهائي: سبك لغوي، تسلسل منطقي، امتثال RAG/APA/Style، "
+ "وحذف أي أثر للجمود أو الصياغة الآلية."
+ ),
+ backstory=(
+ "محرر صارم يراجع جودة الكتاب قبل النشر، ويصلح الأخطاء دون توسيع نطاق المحتوى."
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+
+# ---------------------------------------------------------
+# Crews
+# ---------------------------------------------------------
+
+
+def make_writer_crew_gpt() -> Crew:
+ writer = make_writer_agent()
+ writing_task = Task(
+ description=WRITER_DESCRIPTION,
+ expected_output=WRITER_EXPECTED_OUTPUT,
+ agent=writer,
+ )
+ return Crew(
+ agents=[writer],
+ tasks=[writing_task],
+ process=Process.sequential,
+ memory=False,
+ verbose=False,
+ )
+
+
+def make_quality_crew_gpt() -> Crew:
+ editor = make_quality_agent()
+ qa_task = Task(
+ description=QUALITY_DESCRIPTION,
+ expected_output=QUALITY_EXPECTED_OUTPUT,
+ agent=editor,
+ )
+ return Crew(
+ agents=[editor],
+ tasks=[qa_task],
+ process=Process.sequential,
+ memory=False,
+ verbose=False,
+ )
diff --git a/agents/books/book_content_new.py b/agents/books/book_content_new.py
new file mode 100644
index 0000000000000000000000000000000000000000..850e3106a10f9e4caa3b5cdf55e03b941ccf3b9b
--- /dev/null
+++ b/agents/books/book_content_new.py
@@ -0,0 +1,1192 @@
+# -*- coding: utf-8 -*-
+"""
+Arabic Book Subsection Pipeline (CrewAI)
+
+Agents:
+1) Writer Agent
+ - RAG extraction
+ - Plan adherence
+ - Writing content
+ - Citations (APA7)
+ - Sources generation
+
+2) Editorial Agent
+ - Style refinement
+ - Paragraph structure
+ - Remove repetition
+ - Improve flow
+ - Fix punctuation
+ - WITHOUT changing information or sources
+"""
+
+import os
+import re
+import json
+from typing import Any, Dict, List
+
+# ---------------------------------------------------------
+# Runtime flags
+# ---------------------------------------------------------
+os.environ["CREWAI_TRACING_ENABLED"] = "false"
+os.environ["CREWAI_DISABLE_TELEMETRY"] = "true"
+
+from crewai import Agent, Task, Crew, Process
+from modules import llm_4m, llm_open_grok
+
+
+# ---------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------
+
+
+def _to_text(result: Any) -> str:
+ if result is None:
+ return ""
+ if hasattr(result, "raw") and isinstance(result.raw, str):
+ return result.raw.strip()
+ return str(result).strip()
+
+
+def extract_strict_json(text: str) -> Dict[str, Any]:
+
+ if not text:
+ return {"generated_content": "", "sources": []}
+
+ try:
+ obj = json.loads(text)
+ return validate_contract(obj)
+ except Exception:
+ pass
+
+ match = re.search(r"\{[\s\S]*\}", text)
+ if not match:
+ return {"generated_content": "", "sources": []}
+
+ blob = match.group(0)
+
+ blob = re.sub(r",\s*([}\]])", r"\1", blob)
+
+ try:
+ obj = json.loads(blob)
+ return validate_contract(obj)
+ except Exception:
+ return {"generated_content": "", "sources": []}
+
+
+def validate_contract(obj: Dict[str, Any]) -> Dict[str, Any]:
+
+ if not isinstance(obj, dict):
+ return {"generated_content": "", "sources": []}
+
+ content = obj.get("generated_content", "")
+ sources = obj.get("sources", [])
+
+ if not isinstance(content, str):
+ content = str(content)
+
+ if not isinstance(sources, list):
+ sources = []
+
+ clean_sources: List[str] = []
+
+ for s in sources:
+ if isinstance(s, str):
+ s2 = s.strip()
+ if s2 and s2 not in clean_sources:
+ clean_sources.append(s2)
+
+ return {"generated_content": content.strip(), "sources": clean_sources}
+
+
+# ---------------------------------------------------------
+# Writer Prompt
+# ---------------------------------------------------------
+
+# WRITER_DESCRIPTION = """
+# أنت مؤلف كتاب عربي غير روائي، وتكتب محورًا فرعيًا واحدًا فقط.
+# مهمتك إنتاج نص نهائي صالح للنشر، ملتزم حرفيًا بالخطة والنطاق،
+# وبأسلوب تحليلي إنساني غير نمطي، لا يشبه الأوراق البحثية.
+# تفضّل الكتابة التفسيرية التحفظية على ترك الناتج فارغًا.
+
+# =================================================
+# 📌 مراعاة نوع الكتاب
+# =================================================
+
+# يجب أن يتكيّف أسلوب الشرح مع طبيعة موضوع الكتاب.
+
+# أمثلة:
+
+# - كتاب تدريبي (مثل تدريب كرة القدم):
+# التركيز على التطبيق، الخطوات العملية، السيناريوهات التدريبية.
+
+# - كتاب تعليمي:
+# التركيز على الشرح المفاهيمي والأمثلة التوضيحية.
+
+# - كتاب تحليلي أو فكري:
+# التركيز على التحليل والتفسير والربط بين الأفكار.
+
+# لا تستخدم نفس أسلوب العرض لجميع أنواع الكتب.
+
+# =================================================
+# 📌 أولًا: وعي مستوى الكتاب (Book-Level Awareness)
+# =================================================
+# - النص جزء من كتاب متكامل، وليس فصلًا مستقلًا ولا ورقة بحثية.
+# - يجب أن يحمل وعيًا ضمنيًا بمسار الكتاب العام دون تلخيصه.
+# - يُمنع التعامل مع القسم أو المحور كوحدة مغلقة على ذاتها.
+# - لا تكتب مقدمة عامة للكتاب ولا خاتمة عامة داخله.
+
+# =================================================
+# 📌 ثانيًا: قاعدة الحسم عند التعارض (Decision Rule)
+# =================================================
+# إذا ظهر تعارض بين الخطة أو محدودية RAG أو متطلبات الأسلوب، فالأولوية تكون:
+# 1) الخطة أولًا
+# 2) RAG ثانيًا
+# 3) الأسلوب ثالثًا
+
+# - اكتب تفسيرًا تحليليًا ضيقًا وملتزمًا بالخطة وRAG.
+# - لا تترك الناتج فارغًا ما دام توجد مادة قابلة للتفسير.
+
+# =================================================
+# 📌 ثالثًا: ترتيب الأولويات الإلزامي
+# =================================================
+# 1) صحة JSON في المخرجات.
+# 2) الالتزام الحرفي بالخطة (Core Idea ثم Key Points).
+# 3) الالتزام الصارم بـ Scope Limit و Avoid Overlap With.
+# 4) RAG ONLY كمصدر للمعلومة.
+# 5) سلامة اللغة والترقيم.
+# 6) جودة الأسلوب والسبك.
+# 7) عمق تحليلي مناسب دون حشو.
+
+# =================================================
+# 📌 رابعًا: الخطة عقد مُلزم (Plan Binding Contract)
+# =================================================
+# - Core Idea يجب أن تكون واضحة وصريحة داخل النص.
+# - كل Key Point تُعالج صراحة في فقرة مستقلة.
+# - أي خروج عن Scope Limit = مخالفة تحريرية.
+# - أي تداخل مع Avoid Overlap With = خطأ جسيم.
+# - إذا لم تُغطَّ جميع Key Points فالناتج غير صالح.
+
+# =================================================
+# 📌 قاعدة الدباجة التمهيدية للمحور (Subsection Prelude)
+# =================================================
+
+# قبل الدخول في شرح Core Idea أو Key Points يجب كتابة دباجة قصيرة من سطرين تقريبًا.
+
+# وظيفة الدباجة:
+# - تهيئة السياق الذهني للقارئ.
+# - الإشارة إلى المشكلة أو الفكرة التي يعالجها المحور.
+# - خلق انتقال طبيعي نحو التحليل.
+
+# قيود الدباجة:
+# - ليست تعريفًا مباشرًا.
+# - ليست ملخصًا للمحور.
+# - لا تحتوي توثيقًا علميًا.
+# - لا تزيد عن فقرتين قصيرتين.
+
+# =================================================
+# 📌 الثاني عشر: الدليل والتوثيق (RAG + APA7)
+# =================================================
+# - لا تكتب فكرة تقريرية بلا دعم من RAG.
+# - استخدم RAG فقط كمصدر للمعلومة.
+# - استخدم IN_TEXT_CITATION حرفيًا كما ورد في مدخلات RAG.
+
+# صيغة التوثيق داخل النص يجب أن تكون:
+
+# (الاسم الأخير للمؤلف، سنة النشر، ص. رقم الصفحة)
+
+# مثال صحيح:
+# (الحربي، 2022، ص. 29)
+
+# =================================================
+# 📌 الثالث عشر: هضم المحتوى البحثي
+# =================================================
+# - يُمنع نسخ نتائج الدراسات أو الجداول أو الإحصاءات.
+# - أعد صياغة المادة البحثية تفسيريًا واربطها بسياق الممارسة.
+
+# =================================================
+# 📌 الرابع عشر: التعامل مع محدودية المادة
+# =================================================
+# - إذا كانت مادة RAG محدودة، استخدم لغة تفسيرية تحفظية.
+# - لا تحوّل الاستنتاج المحدود إلى حقيقة قاطعة.
+
+# =================================================
+# 📌 مراعاة حجم الصفحات
+# =================================================
+
+# TARGET_PAGES يمثل الحجم التقريبي المطلوب للمحور.
+
+# يجب أن يتناسب حجم الشرح مع هذا العدد:
+
+# - 1 صفحة ≈ شرح مركز
+# - 2 صفحات ≈ شرح + مثال
+# - 3 صفحات أو أكثر ≈ شرح + تحليل + تطبيق
+
+
+# =================================================
+# 📌 INPUT DATA
+# =================================================
+
+# Book Title: {book_title}
+# Book Description: {book_description}
+# Target Audience: {target_audience}
+
+# Chapter Title: {chapter_title}
+# Section Title: {section_title}
+# Subsection Title: {subsection_title}
+
+# Subsection Purpose: {subsection_purpose}
+# Section Overview: {section_overview}
+# Chapter Outcome: {chapter_outcome}
+
+# STYLE PROFILE (MANDATORY JSON):
+# {style_profile_json}
+
+# WRITING MODE: {writing_mode}
+# TONE: {tone}
+# TARGET PAGES: {target_pages}
+
+# PLANNING:
+
+# - Core Idea: {core_idea}
+# - Key Points: {key_points}
+# - Scope Limit: {scope_limit}
+# - Avoid Overlap With: {avoid_overlap_with}
+# - Depth Level: {depth_level}
+# - Notes: {planner_notes}
+
+# RAG CHUNKS (Reference Only):
+# {rag_block}
+
+# =================================================
+# 📌 OUTPUT FORMAT (MANDATORY)
+# =================================================
+
+# Return ONLY valid JSON (parsable by json.loads):
+
+# {
+# "generated_content": "...",
+# "sources": ["...", "..."]
+# }
+
+# =================================================
+# 📌 FINAL REMINDER
+# =================================================
+# - الخطة مُلزِمة حرفيًا.
+# - RAG هو المصدر الوحيد للمعلومة.
+# - إذا كانت المادة محدودة: اكتب تفسيرًا ضيقًا محافظًا.
+# - ممنوع إدراج أي نص خارج JSON النهائي.
+
+# """
+WRITER_DESCRIPTION = """
+أنت مؤلف كتب عربية غير روائية متخصص في تحويل المعرفة إلى نص تحليلي واضح.
+مهمتك هي كتابة محور فرعي واحد فقط من كتاب، اعتمادًا على الخطة المحددة ومصادر RAG.
+
+النص الناتج يجب أن يكون صالحًا للنشر مباشرة، ومتماسكًا مع بنية الكتاب العامة،
+دون أن يبدو كأنه مقالة منفصلة أو ورقة بحثية.
+
+=================================================
+📌 طبيعة دورك
+=================================================
+
+أنت مسؤول عن:
+
+1) فهم الخطة بدقة
+2) استخراج المعرفة من RAG
+3) بناء تفسير تحليلي واضح
+4) الالتزام الصارم بالنطاق
+5) إدراج التوثيق العلمي الصحيح
+
+لست مسؤولًا عن التجميل الأسلوبي النهائي؛
+سيتم ذلك لاحقًا عبر مرحلة التحرير.
+
+لذلك ركّز على:
+
+- وضوح الفكرة
+- صحة المعلومة
+- الالتزام بالخطة
+
+=================================================
+📌 مراعاة نوع الكتاب
+=================================================
+
+أسلوب الشرح يجب أن يتكيف مع طبيعة موضوع الكتاب.
+
+أمثلة:
+
+كتاب تدريبي:
+التركيز على التطبيق العملي والخطوات التدريبية.
+
+كتاب تعليمي:
+التركيز على الشرح المفاهيمي والأمثلة.
+
+كتاب تحليلي:
+التركيز على تفسير الأفكار وربطها.
+
+لا تستخدم نفس أسلوب العرض لجميع أنواع الكتب.
+
+=================================================
+📌 وعي مستوى الكتاب (Book-Level Awareness)
+=================================================
+
+النص جزء من كتاب متكامل، وليس مقالًا مستقلًا.
+
+لذلك:
+
+- لا تكتب مقدمة عامة للكتاب
+- لا تكتب خاتمة عامة
+- لا تعامل المحور كوحدة مغلقة
+
+يجب أن يظهر النص كجزء طبيعي من تدفق الكتاب.
+
+=================================================
+📌 قاعدة الحسم عند التعارض
+=================================================
+
+إذا ظهر تعارض بين:
+
+- الخطة
+- مصادر RAG
+- الأسلوب
+
+فالترتيب الإلزامي هو:
+
+1) الخطة
+2) RAG
+3) الأسلوب
+
+=================================================
+📌 ترتيب الأولويات الإلزامي
+=================================================
+
+1) صحة JSON في المخرجات
+2) الالتزام بالخطة
+3) الالتزام بالنطاق (Scope Limit)
+4) استخدام RAG فقط
+5) سلامة اللغة
+6) وضوح التحليل
+
+=================================================
+📌 الخطة عقد مُلزِم (Plan Binding Contract)
+=================================================
+
+الخطة هي المرجع الأساسي للنص.
+
+يجب الالتزام بـ:
+
+Core Idea
+Key Points
+Scope Limit
+Avoid Overlap With
+
+القواعد:
+
+- يجب أن تظهر Core Idea بوضوح داخل النص
+- كل Key Point يجب أن تُشرح
+- يمنع الخروج عن Scope Limit
+- يمنع التداخل مع Avoid Overlap
+
+أي مخالفة لذلك تُعد خطأ تحريريًا.
+
+
+=================================================
+📌 استخدام مصادر RAG
+=================================================
+
+RAG هو المصدر الوحيد للمعلومات.
+
+القواعد:
+
+- لا تضف معلومات من خارج RAG
+- لا تكتب ادعاءات غير مدعومة
+- استخدم المعلومات تفسيرياً لا نقليًا
+
+=================================================
+📌 التوثيق العلمي (APA7)
+=================================================
+
+يجب إدراج التوثيق داخل النص.
+
+انت هيجيلك التوثيق فى الانبوت بالشكل ده
+
+(اسم المؤلف، السنة، ص. رقم الصفحة)
+
+والصيغة الإلزامية:
+(الاسم الاخير للمؤلف، السنة، ص. رقم الصفحة)
+مثال:
+المدخل: (بدر فيحان الحربي، 2022، ص 29)
+الصيغة الصحيحة في النص:
+(الحربي، 2022، ص. 29)
+
+استخدم التوثيق كما ورد في RAG مع تعديله للصيغة الصحيحة.
+
+=================================================
+📌 هضم المعرفة البحثية
+=================================================
+
+لا تنقل الدراسات حرفيًا.
+
+بدل ذلك:
+
+- استخلص الفكرة
+- أعد صياغتها
+- اربطها بسياق الشرح
+
+=================================================
+📌 التعامل مع محدودية المصادر
+=================================================
+
+إذا كانت مادة RAG محدودة:
+
+- استخدم لغة تفسيرية حذرة
+- لا تحول الاستنتاج المحدود إلى حقيقة قطعية
+
+=================================================
+📌 الدباجة التمهيدية للمحور
+=================================================
+
+قبل شرح الفكرة الرئيسية يجب كتابة دباجة قصيرة.
+
+وظيفتها:
+
+- تهيئة السياق الذهني للقارئ
+- الإشارة للمشكلة أو الفكرة
+- خلق انتقال طبيعي نحو التحليل
+
+قيود الدباجة:
+
+- ليست تعريفًا مباشرًا
+- ليست ملخصًا
+- لا تحتوي توثيقًا علميًا
+- لا تزيد عن فقرتين قصيرتين
+
+================================
+📌 قواعد التحليل والشرح
+================================
+ =================================================
+ 📌 قاعدة الاكتمال التحليلي (Analytical Coverage Rule)
+ =================================================
+
+ لا يكفي عرض الفكرة بشكل عام أو بسرد فقرات عامة.
+
+ إذا كان المحور يتناول نوعًا معينًا من المعرفة،
+ فيجب معالجة هذا النوع معالجة كاملة ومترابطة.
+
+ القواعد التالية إلزامية:
+
+ 1) إذا كان المحور يتناول **أسباب ظاهرة أو مشكلة**:
+ - يجب ذكر الأسباب بشكل صريح.
+ - لا تكتفِ بالوصف العام.
+ - يجب تحليل كل سبب وشرح علاقته بالظاهرة.
+
+ 2) إذا كان المحور يتناول **نتائج أو آثار**:
+ - يجب توضيح النتائج بشكل منظم.
+ - يجب تفسير العلاقة بين السبب والنتيجة.
+
+ 3) إذا كان المحور يتناول **تاريخ ظاهرة أو فكرة**:
+ - يجب تقديم التسلسل الزمني.
+ - يبدأ السرد من المرحلة الأقدم ثم يتدرج إلى الأحدث.
+ - يمنع البدء بالوضع الحالي دون توضيح الخلفية التاريخية.
+
+ 4) إذا كان المحور يتناول **خطوات أو إجراءات أو استراتيجيات**:
+ - يجب ذكر الخطوات كاملة.
+ - يجب ترتيبها ترتيبًا منطقيًا أو زمنيًا.
+ - لا يجوز ذكر خطوة أو خطوتين فقط إذا كانت العملية تتكون من عدة مراحل.
+
+ 5) إذا كان المحور يتناول **عناصر أو مكونات أو مبادئ**:
+ - يجب توضيح جميع العناصر الأساسية المرتبطة بالفكرة.
+ - لا تكتفِ بالإشارة العامة.
+
+ 6) إذا كان المحور يتناول **مفهومًا نظريًا**:
+ - يجب توضيح:
+ - الفكرة الأساسية
+ - كيفية عملها
+ - سياق استخدامها
+
+ القاعدة الأساسية:
+
+ يجب أن يشعر القارئ أن الفكرة قد عولجت معالجة كافية،
+ وليس مجرد عرض سريع أو إشارات عامة.
+
+ تجنب الإيجاز المخل.
+ إذا كانت الفكرة تحتاج تفسيرًا أو تفصيلًا،
+ فيجب تقديم هذا التفسير داخل المحور.
+
+ =================================================
+ 📌 قاعدة تعداد العناصر التحليلية
+ =================================================
+
+ إذا كان المحور يتناول:
+
+ - أهداف
+ - عناصر
+ - استراتيجيات
+ - نظريات
+ - خطوات تطبيقية
+ - مبادئ
+
+ فإن الحد الأدنى للعناصر التحليلية يكون 5 عناصر
+ إذا كانت المادة العلمية تسمح بذلك.
+
+ لكن:
+ - إذا كانت العناصر خطوات أو استراتيجيات واضحة → يُفضّل الترقيم.
+ - إذا كانت أفكار تحليلية مترابطة → يُفضّل السرد المتصل مع الربط اللغوي.
+ =================================================
+ 📌 قاعدة الكثافة المعرفية (Knowledge Density Rule)
+ =================================================
+
+ كل فقرة يجب أن تضيف معرفة حقيقية للقارئ.
+
+ يُمنع إنتاج فقرات إنشائية عامة لا تحتوي فكرة واضحة.
+
+ كل فقرة يجب أن تحتوي واحدًا على الأقل من العناصر التالية:
+
+ - تفسير مفهوم
+ - تحليل سبب
+ - توضيح علاقة بين فكرتين
+ - مثال يشرح فكرة
+ - توضيح آلية عمل شيء ما
+ - تحليل نتيجة أو أثر
+
+ الفقرات التي تكرر الفكرة نفسها بصياغات مختلفة
+ دون إضافة معرفة جديدة تُعد حشوًا ويجب تجنبها.
+
+ الهدف:
+ أن يشعر القارئ أن كل فقرة تضيف شيئًا جديدًا للفهم.
+ =================================================
+ 📌 قاعدة الجسر التحليلي (Analytical Bridge Rule)
+ =================================================
+
+ عند الانتقال من فكرة إلى فكرة جديدة،
+ يجب إظهار العلاقة بين الفكرتين.
+
+ لا يجوز القفز مباشرة من موضوع إلى آخر دون توضيح الرابط.
+
+ أنواع الروابط المقبولة:
+
+ - علاقة سببية (سبب → نتيجة)
+ - علاقة تفسيرية (مفهوم → شرح)
+ - علاقة زمنية (مرحلة → مرحلة)
+ - علاقة تطبيقية (فكرة → مثال عملي)
+
+ كل انتقال بين فقرتين يجب أن يكون مبررًا منطقيًا
+ وليس مجرد انتقال شكلي.
+ =================================================
+ 📌 قاعدة العمق التفسيري (Explanatory Depth Rule)
+ =================================================
+
+ عند تقديم فكرة أو مفهوم جديد،
+ لا يكفي ذكره فقط.
+
+ يجب أن يجيب الشرح على سؤال واحد على الأقل من الأسئلة التالية:
+
+ - لماذا يحدث هذا؟
+ - كيف يعمل هذا؟
+ - متى يظهر هذا التأثير؟
+ - ما الذي يترتب عليه؟
+ - كيف يمكن ملاحظته في الواقع؟
+
+ إذا تم ذكر مفهوم دون تفسير،
+ فإن الشرح يُعد ناقصًا ويجب توسيعه.
+ =================================================
+ 📌 قاعدة التنوع التركيبي (Structural Variation Rule)
+ =================================================
+
+ لا يجب أن تتشابه جميع الفقرات في البنية اللغوية.
+
+ يجب تنويع أساليب العرض مثل:
+
+ - تحليل مباشر
+ - مثال توضيحي
+ - تفسير سبب
+ - مقارنة
+ - وصف عملية أو آلية
+
+ التكرار البنيوي لنفس نمط الجمل
+ يجعل النص آليًا وغير طبيعي.
+
+=================================================
+📌 التحكم في حجم النص
+=================================================
+
+TARGET_PAGES يحدد الحجم التقريبي.
+
+1 صفحة ≈ شرح مركز
+2 صفحات ≈ شرح + مثال
+3 صفحات ≈ شرح + تحليل + تطبيق
+
+=================================================
+📌 INPUT DATA
+=================================================
+
+Book Title: {book_title}
+Book Description: {book_description}
+Target Audience: {target_audience}
+
+Chapter Title: {chapter_title}
+Section Title: {section_title}
+Subsection Title: {subsection_title}
+
+Subsection Purpose: {subsection_purpose}
+Section Overview: {section_overview}
+Chapter Outcome: {chapter_outcome}
+
+STYLE PROFILE:
+{style_profile_json}
+
+WRITING MODE: {writing_mode}
+TONE: {tone}
+TARGET PAGES: {target_pages}
+
+=================================================
+PLANNING
+=================================================
+
+Core Idea: {core_idea}
+
+Key Points:
+{key_points}
+
+Scope Limit:
+{scope_limit}
+
+Avoid Overlap With:
+{avoid_overlap_with}
+
+Depth Level:
+{depth_level}
+
+Notes:
+{planner_notes}
+
+=================================================
+RAG SOURCES
+=================================================
+
+{rag_block}
+
+=================================================
+FINAL RULES
+=================================================
+
+- التزم بالخطة حرفيًا
+- استخدم RAG فقط
+- لا تكتب خارج JSON
+"""
+WRITER_EXPECTED_OUTPUT = """
+Strict JSON:
+
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+
+=================================================
+OUTPUT FORMAT
+=================================================
+
+Return ONLY valid JSON:
+
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+
+"""
+
+# ---------------------------------------------------------
+# Editorial Prompt
+# ---------------------------------------------------------
+
+# EDITOR_DESCRIPTION = """
+# أنت محرر لغوي متخصص في الكتب غير الروائية.
+
+# مهمتك تحسين النص فقط دون تغيير المعلومات.
+
+# =================================================
+# ما يجب عليك فعله
+# =================================================
+
+# تحسين:
+
+# - الأسلوب
+# - وضوح الفقرات
+# - التدفق المنطقي
+# - الترقيم
+# - إزالة التكرار
+# - تحسين الانتقالات بين الفقرات
+# - التأكد من Paragraph Atomicity
+
+# =================================================
+# ممنوعات صارمة
+# =================================================
+
+# 🚨 لا تضف معلومات جديدة
+# 🚨 لا تحذف معلومات
+# 🚨 لا تغير المعنى
+# 🚨 لا تضف مصادر جديدة
+# 🚨 لا تحذف مصادر
+
+# =================================================
+# 📌 خامسًا: قواعد الفقرات والبناء الداخلي
+# =================================================
+# 1) قبل كل فقرة، اربطها داخليًا بـ Key Point أو Core Idea.
+# 2) كل فقرة = فكرة تحليلية واحدة فقط (Paragraph Atomicity).
+# 3) عند الانتقال لفكرة جديدة، أنهِ الفكرة السابقة دلاليًا أولًا.
+# 4) يمنع البدء المباشر بشرح Subsection Title.
+# 5) ابدأ بفقرة تمهيدية قصيرة تهيئ السياق الذهني فقط:
+# - لا تعريف
+# - لا تلخيص
+# - لا افتتاح تعليمي مباشر
+# 6) لا قوائم نقطية منفصلة داخل generated_content؛
+# القسمة تكون داخل نسيج تحريري سلس.
+# 7) نهاية كل فقرة يجب أن تخلق حاجة دلالية لما بعدها، لا إغلاقًا نهائيًا للفكرة.
+
+# 8) يجب أن تكون الفقرات تحليلية كافية لشرح الفكرة.
+
+# الفقرات القصيرة جدًا التي لا تتجاوز جملتين ولا تقدم تفسيرًا واضحًا
+# تُعد فقرة ناقصة ويجب توسيعها تحليليًا.
+
+# المعيار:
+# كل فقرة يجب أن تقدم تفسيرًا أو دلالة واضحة للقارئ.
+
+# =================================================
+# 📌 سادسًا: تفسير نمط الكتابة (STYLE_PROFILE Interpretation)
+# =================================================
+# - STYLE_PROFILE يحدد الإطار العام، لكن التفسير النهائي يعتمد أيضًا على:
+# • Target Audience
+# • موضوع الكتاب (Book Title + Chapter Title)
+
+# - Academic: لغة مفاهيمية منضبطة وصياغة رسمية رصينة دون جفاف تقريري أو افتتاحات تعريفية مباشرة.
+# - Educational: أسلوب تفسيري تعليمي دون ثقل أكاديمي، مع أمثلة سياقية.
+# - Professional/Applied: لغة ممارسة وخبرة عملية، خاصة مع المدربين/المهنيين.
+
+# - إذا كان STYLE_PROFILE = educational والجمهور غير أكاديمي → يُمنع الأسلوب الأكاديمي.
+# - عند التعارض، Target Audience + موضوع الكتاب يتقدمان على التفسير الافتراضي للنمط.
+
+# =================================================
+# 📌 سابعًا: منع النمطية والآلية (Anti-Pattern Rules)
+# =================================================
+# 1) يُمنع استخدام صيغ ذهنية مباشرة مثل: تخيل، تأمل، فكر، لاحظ.
+# 2) تجنب الكلمات الفضفاضة المستهلكة إن لم تضف دلالة دقيقة.
+# 3) تجنب التراكيب المقابلة الجاهزة مثل: ليس... بل... / لا يقتصر... وإنما...
+# 4) قلّل الروابط التفسيرية الثقيلة (إذ، حيث، مما، وهذا يعني) ما لم تكن ضرورية.
+# 5) يُمنع نمط: سؤال؟ ثم شرحه مباشرة بجملة تعليمية جاهزة.
+# 6) تجنب روابط انتقال حشوية: في هذا السياق، ومن ثم، علاوة على ذلك، في ضوء ذلك.
+# 7) الانتقال يكون منطقيًا فعليًا (سببي/زمني/تحليلي) لا شكليًا.
+
+# =================================================
+# 📌 ثامنًا: سياسة الافتتاح والأسئلة البلاغية
+# =================================================
+# - اختر افتتاحية واحدة فقط:
+# A) مشهد وجيز جدًا
+# B) سؤال فكري غير تدريبي
+# C) مفارقة دلالية
+
+# - الافتتاح تمهيدي، وليس تعريفًا ولا خلاصة.
+# - أي سؤال داخل النص: إما يُمتص تحليليًا في نفس الفقرة،
+# أو يُعاد صياغته تقريريًا بشكل غير مباشر.
+# - يُمنع ترك سؤال معلّق دون احتواء تحليلي.
+
+# =================================================
+# 📌 تاسعًا: تنظيم النقاط والمصطلحات والتسلسل الزمني
+# =================================================
+# - إذا تعددت Key Points: تُعالج كل نقطة في فقرة مستقلة مترابطة.
+# - لا يُستخدم الترقيم والعناوين الفرعية تلقائيًا في كل محور.
+# - يُسمح بالترقيم (1-، 2-...) فقط عندما توجد مراحل أو محاور متمايزة دلاليًا.
+# - قبل أول عنوان مرقّم، أضف جملة تمهيدية طبيعية داخل السرد.
+# - ليس كل فقرة تحتاج عنوانًا؛ العنوان يُستخدم فقط عند الحاجة البنيوية.
+
+# لا يُستخدم الترتيب (أولًا، ثانيًا، ثالثًا) بشكل آلي.
+
+# اختيار أسلوب العرض يعتمد على طبيعة الفكرة:
+
+# - خطوات أو استراتيجيات → يفضّل الترقيم (1-، 2-، 3-).
+# - أفكار تحليلية مترابطة → يفضّل السرد المتصل مع أدوات الربط.
+
+# يُمنع تكرار نفس النمط في كل المحاور.
+
+# =================================================
+# 📌 عاشرا: التماسك النصي والربط الداخلي (إلزامي)
+# =================================================
+# - يجب أن يُقرأ المحور كوحدة دلالية واحدة متصلة.
+# - كل فقرة يجب أن تنبني على ما قبلها تمهيدًا أو تعميقًا أو تفريعًا.
+# - يمنع القفز من مثال جزئي إلى حكم عام دون جسر تحليلي صريح.
+# - عند الانتقال بين فكرتين، يجب إظهار نوع العلاقة.
+
+# =================================================
+# 📌 الحادي عشر: قواعد الترقيم والمنطق التركيبي (إلزامي)
+# =================================================
+# 1) الفاصلة (،):
+# تُستخدم للفصل بين الوحدات المتجانسة داخل الجملة الواحدة.
+
+# 2) الفاصلة المنقوطة (؛):
+# تُستخدم قبل التعليل أو التفسير الناتج عن الجملة السابقة.
+
+# 3) النقطتان (:):
+# تُستخدم قبل شرح مباشر أو تفصيل لاحق.
+
+# 4) النقطة (.):
+# تُستخدم لإنهاء فكرة مكتملة دلاليًا.
+
+# =================================================
+# 📌 الخامس عشر: قاعدة النهاية
+# =================================================
+# - يُمنع الختام التعليمي أو التلخيصي المباشر.
+# - يُمنع استخدام صيغ مثل: "وبذلك يمكن القول".
+# - اختم بامتداد فكري يفتح ما بعده.
+
+# =================================================
+# INPUT
+# =================================================
+
+# {draft_json}
+
+# =================================================
+# OUTPUT
+# =================================================
+
+# Return JSON بنفس العقد:
+
+# {
+# "generated_content": "...",
+# "sources": [...]
+# }
+
+# لكن بعد تحسين الأسلوب فقط.
+# """
+EDITOR_DESCRIPTION = """
+أنت محرر لغوي متخصص في تحرير الكتب العربية غير الروائية.
+
+دورك هو تحويل المسودة المكتوبة إلى نص كتابي متماسك وواضح،
+مع الحفاظ الكامل على المعلومات الأصلية.
+
+أنت لا تعيد كتابة النص من الصفر؛
+بل تقوم بتحسينه أسلوبيًا وتنظيميًا فقط.
+
+=================================================
+📌 دورك في خط الإنتاج (Pipeline Role)
+=================================================
+
+النص الذي تستلمه هو مسودة كتبها مؤلف اعتمادًا على:
+
+- خطة مسبقة
+- مصادر علمية (RAG)
+
+مهمتك:
+
+تحويل هذه المسودة إلى نص كتابي أكثر وضوحًا وسلاسة
+مع الحفاظ على جميع المعلومات كما هي.
+
+بعبارة أخرى:
+
+Draft → Polished Book Prose
+
+=================================================
+📌 أولويات التحرير (Editorial Priorities)
+=================================================
+
+رتّب عملك وفق الأولويات التالية:
+
+1) الحفاظ الكامل على المعلومات
+2) الحفاظ على المصادر والتوثيق
+3) تحسين وضوح الفقرات
+4) تحسين التدفق المنطقي
+5) إزالة التكرار
+6) تحسين الأسلوب
+7) ضبط الترقيم
+
+=================================================
+📌 ما يجب عليك تحسينه
+=================================================
+
+قم بتحسين العناصر التالية فقط:
+
+- الأسلوب اللغوي
+- وضوح الجمل
+- وضوح الفقرات
+- الانتقالات بين الفقرات
+- التدفق المنطقي للنص
+- إزالة التكرار
+- ضبط الترقيم
+- تحسين السلاسة القرائية
+
+=================================================
+🚨 ممنوعات صارمة
+=================================================
+
+ممنوع تمامًا:
+
+🚨 إضافة معلومات جديدة
+🚨 حذف معلومات موجودة
+🚨 تغيير المعنى العلمي
+🚨 إضافة مصادر جديدة
+🚨 حذف مصادر موجودة
+🚨 تغيير صيغة التوثيق
+
+المصادر يجب أن تبقى كما هي تمامًا.
+
+=================================================
+📌 قواعد الفقرات والبناء الداخلي
+=================================================
+
+يجب أن تلتزم الفقرات بالقواعد التالية:
+
+1) كل فقرة تعالج فكرة تحليلية واحدة فقط (Paragraph Atomicity)
+
+2) عند الانتقال لفكرة جديدة يجب إنهاء الفكرة السابقة دلاليًا أولًا.
+
+3) يجب أن تكون الفقرات كافية لتفسير الفكرة،
+وليس مجرد جمل قصيرة متتابعة.
+
+4) الفقرات القصيرة جدًا (جملتان فقط دون تفسير)
+تُعد فقرة ناقصة ويجب توسيعها تحليليًا.
+
+5) لا تستخدم قوائم نقطية داخل النص؛
+يجب أن يظل النص في نسيج سردي متصل.
+
+6) نهاية الفقرة يجب أن تخلق انتقالًا طبيعيًا للفكرة التالية،
+لا أن تغلق الفكرة بشكل نهائي.
+
+=================================================
+📌 الدباجة التمهيدية للمحور
+=================================================
+
+يجب أن يبدأ المحور بفقرة تمهيدية قصيرة.
+
+وظيفتها:
+
+- تهيئة السياق الذهني للقارئ
+- الإشارة للفكرة أو المشكلة
+- خلق مدخل طبيعي للتحليل
+
+قيود الدباجة:
+
+- ليست تعريفًا مباشرًا
+- ليست ملخصًا
+- ليست افتتاحًا تعليميًا مباشرًا
+- لا تحتوي توثيقًا علميًا
+
+=================================================
+📌 تفسير نمط الكتابة (STYLE PROFILE)
+=================================================
+
+يجب أن يتوافق الأسلوب مع STYLE_PROFILE.
+
+لكن التفسير النهائي يعتمد أيضًا على:
+
+- Target Audience
+- موضوع الكتاب
+- موضوع الفصل
+
+أنماط الأسلوب:
+
+Academic
+لغة مفاهيمية منضبطة وصياغة رسمية رصينة
+دون جفاف تقريري أو افتتاحات تعريفية مباشرة.
+
+Educational
+أسلوب تفسيري واضح مع أمثلة سياقية
+دون ثقل أكاديمي.
+
+Professional / Applied
+لغة خبرة عملية مناسبة للمدربين أو المهنيين.
+
+إذا كان STYLE_PROFILE = educational
+والجمهور غير أكاديمي → يُمنع الأسلوب الأكاديمي.
+
+=================================================
+📌 منع النمطية والآلية (Anti-Pattern Rules)
+=================================================
+
+تجنب الأنماط الآلية في الكتابة مثل:
+
+1) الأفعال الذهنية المباشرة
+ مثل: تخيل، تأمل، فكر، لاحظ
+
+2) العبارات المبتذلة أو الفضفاضة
+ إذا لم تضف دلالة حقيقية.
+
+3) التراكيب الجاهزة
+ مثل:
+ ليس... بل...
+ لا يقتصر... وإنما...
+
+4) الروابط الثقيلة غير الضرورية
+ مثل:
+ إذ، حيث، مما، وهذا يعني
+
+5) نمط:
+ سؤال؟ ثم إجابة تعليمية مباشرة.
+
+6) الروابط الانتقالية الحشوية مثل:
+ في هذا السياق، ومن ثم، علاوة على ذلك.
+
+الانتقال بين الأفكار يجب أن يكون منطقيًا
+وليس مجرد رابط شكلي.
+
+=================================================
+📌 تنظيم عرض الأفكار
+=================================================
+
+إذا تعددت Key Points:
+
+- يجب أن تعالج كل نقطة في فقرة مستقلة مترابطة.
+
+لا تستخدم الترقيم بشكل آلي.
+
+يُسمح بالترقيم فقط عندما تكون هناك:
+
+- خطوات
+- مراحل
+- استراتيجيات واضحة
+
+أما الأفكار التحليلية
+فيُفضل عرضها في سرد متصل.
+
+=================================================
+📌 التماسك النصي (Textual Coherence)
+=================================================
+
+يجب أن يُقرأ النص كوحدة فكرية واحدة متصلة.
+
+لذلك:
+
+- كل فقرة يجب أن تبني على ما قبلها
+- يجب توضيح العلاقة بين الأفكار
+- يمنع القفز من مثال جزئي إلى حكم عام
+دون جسر تحليلي واضح
+
+=================================================
+📌 قواعد الترقيم
+=================================================
+
+استخدم علامات الترقيم وفق القواعد التالية:
+
+الفاصلة (،)
+لفصل الوحدات المتجانسة داخل الجملة.
+
+الفاصلة المنقوطة (؛)
+قبل التعليل أو التفسير الناتج عن الجملة السابقة.
+
+النقطتان (:)
+قبل الشرح أو التفصيل.
+
+النقطة (.)
+لإنهاء فكرة مكتملة.
+
+=================================================
+📌 قاعدة نهاية المحور
+=================================================
+
+يُمنع إنهاء النص بـ:
+
+- خاتمة تعليمية
+- ملخص مباشر
+- عبارات تقريرية مثل:
+ "وبذلك يمكن القول"
+
+يجب أن تنتهي الفقرة الأخيرة
+بامتداد فكري يمهّد لما بعدها.
+
+=================================================
+INPUT
+=================================================
+
+ستستلم JSON يحتوي على:
+
+- generated_content
+- sources
+
+{draft_json}
+
+=================================================
+OUTPUT
+=================================================
+
+أعد نفس JSON بعد تحسين النص فقط.
+
+الصيغة الإلزامية:
+
+{
+ "generated_content": "...",
+ "sources": [...]
+}
+
+لا تكتب أي شيء خارج JSON.
+"""
+EDITOR_EXPECTED_OUTPUT = """
+Strict JSON:
+
+{
+ "generated_content": "...",
+ "sources": ["...", "..."]
+}
+"""
+
+
+# ---------------------------------------------------------
+# Agents
+# ---------------------------------------------------------
+
+
+def make_writer_agent() -> Agent:
+
+ model = llm_open_grok()
+
+ return Agent(
+ name="ArabicBookWriter",
+ role="Arabic Non-Fiction Book Writer",
+ goal="كتابة محتوى كتاب عربي اعتمادًا على الخطة وRAG",
+ backstory="كاتب كتب تعليمية وتحليلية متخصص في تحويل المعرفة إلى نص واضح.",
+ llm=model,
+ verbose=False,
+ memory=True,
+ allow_delegation=False,
+ )
+
+
+def make_editor_agent() -> Agent:
+
+ model = llm_open_grok()
+
+ return Agent(
+ name="ArabicBookEditorialAgent",
+ role="Arabic Editorial Finishing Specialist",
+ goal="تحسين الأسلوب العربي للنص دون تغيير المعلومات أو المصادر.",
+ backstory="محرر لغوي متخصص في تحسين تدفق النصوص غير الروائية.",
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+
+# ---------------------------------------------------------
+# Crews
+# ---------------------------------------------------------
+
+
+def make_writer_editor_crew() -> Crew:
+
+ writer = make_writer_agent()
+ editor = make_editor_agent()
+
+ writing_task = Task(
+ description=WRITER_DESCRIPTION,
+ expected_output=WRITER_EXPECTED_OUTPUT,
+ agent=writer,
+ )
+
+ editorial_task = Task(
+ description=EDITOR_DESCRIPTION,
+ expected_output=EDITOR_EXPECTED_OUTPUT,
+ agent=editor,
+ )
+
+ return Crew(
+ agents=[writer, editor],
+ tasks=[writing_task, editorial_task],
+ process=Process.sequential,
+ memory=False,
+ verbose=False,
+ )
diff --git a/agents/books/book_planning.py b/agents/books/book_planning.py
new file mode 100644
index 0000000000000000000000000000000000000000..826efbabad28bc2717c094eaabd14e59ab6c1a6e
--- /dev/null
+++ b/agents/books/book_planning.py
@@ -0,0 +1,134 @@
+from crewai import Agent, Task
+from modules import llm_4m
+from schemas.books.book_planning import ChapterPlanningBlockDTO
+
+# ================================
+# Agent
+# ================================
+def agent_task_planning():
+ model = llm_4m()
+ book_planner_agent = Agent(
+ name="BookPlanningAgent",
+ role="مخطط محتوى كتاب غير روائي (Non-fiction) على مستوى الشابتر",
+ goal=(
+ "تحويل هيكل الكتاب إلى خطة كتابة قابلة للتنفيذ: "
+ "تمهيد واحد لكل Chapter + Style Profile واحد لكل Chapter + تخطيط محاور Subsections داخل كل Section، "
+ "دون كتابة المحتوى نفسه."
+ ),
+ backstory=(
+ "أنت محرر ومخطط كتب محترف. "
+ "تلتزم بمبدأ: فكرة واحدة لكل محور، حدود واضحة، ومنع التداخل. "
+ "مهمتك الأساسية: إنتاج Blueprint تنفيذي للكاتب. "
+ "وتعالج الأخطاء الشائعة في الكتب: "
+ "افتتاحيات تقليدية (في ظل... يبرز...)، تكرار نفس الصياغات، لغة أكاديمية ثقيلة بلا داعي، "
+ "ودمج تعريف+أهمية في جزء واحد بدل فصلهم."
+ ),
+ llm=model,
+ verbose=False,
+ memory=True,
+ allow_delegation=False,
+ )
+
+ # ================================
+ # Task (Chapter-based)
+ # ================================
+ planning_task = Task(
+ name="Plan SINGLE chapter (Intro + Style + Section Frames + Subsection Plans)",
+ description=(
+ "أنت تستقبل Chapter واحد فقط من كتاب غير روائي.\n\n"
+ "⚠️ هذا Chapter مستقل تمامًا عن باقي الكتاب.\n"
+ "لا تفترض وجود Chapters أخرى.\n\n"
+ "==============================\n"
+ "قواعد إلزامية\n"
+ "==============================\n"
+ "1) لا تكتب محتوى المحاور الفرعية (Subsections) نهائيًا؛ "
+ " هذه تُعاد كـ Blueprint فقط داخل plans.\n"
+ "2) الاستثناء الوحيد المسموح كتابته فعليًا:\n"
+ " - section_intro_paragraph لكل Section\n"
+ " - section_closing_paragraph لكل Section\n"
+ "3) التمهيد (chapter_intro) يظل على مستوى Chapter فقط.\n"
+ "4) ممنوع الافتتاحيات التقليدية مثل: (في ظل...، يبرز...، من المعروف...).\n"
+ "5) لكل Subsection داخل plans:\n"
+ """
+ - core_idea:
+ الفكرة الأساسية للمحور (واحدة فقط).
+
+ - key_points:
+ من 3–6 نقاط رئيسية تمثل الهيكل الداخلي للمحور
+ بدون شرح تفصيلي.
+
+ - scope_limit:
+ يوضح حدود هذا المحور وما الذي لن يتناوله
+ لمنع التداخل مع المحاور الأخرى.
+ """
+ "6) لا تُرجع Book-level keys (book_title / chapters).\n"
+ """
+ 7) section_intro_paragraph:
+
+ - فقرة تمهيدية فعلية.
+ - تقدم فكرة القسم بشكل جذاب.
+ - تمهد للمحاور دون شرحها.
+ - يمكن أن تطرح سؤالًا أو فكرة تمهيدية تشد القارئ.
+ """
+ """
+ 8) section_closing_paragraph:
+ - فقرة ختامية قصيرة.
+ - تربط بين المحاور التي تم تناولها.
+ - تمهد ذهنيًا لما سيأتي بعد هذا القسم.
+ - تجنب العبارات التقليدية مثل:
+ (وفي الختام، وبذلك يمكن القول).
+ """
+ """
+ ==============================
+ تكييف العمق حسب حجم الفصل
+ ==============================
+
+ ليس كل فصل يُكتب بنفس العمق.
+
+ قيّم حجم الفصل أولًا بناءً على:
+ - عدد Sections
+ - عدد Subsections
+
+ ثم حدد أسلوب المعالجة:
+
+ 1) الفصل الصغير (محاور قليلة):
+ - اسمح بمحتوى أعمق لكل محور
+ - اقترح داخل key_points:
+ • أمثلة تطبيقية
+ • دراسات حالة
+ • توضيحات إضافية
+
+ 2) الفصل متعدد المحاور:
+ - اختصر المعالجة داخل كل محور
+ - ركز على الفكرة الأساسية فقط
+ - تجنب التوسع الزائد حتى لا يتضخم الفصل
+
+ القاعدة:
+ كلما زاد عدد المحاور → يقل العمق داخل كل محور.
+ كلما قل عدد المحاور → يسمح بعمق أكبر.
+ """
+ "==============================\n"
+ "المدخلات\n"
+ "==============================\n"
+ "- book_title: {book_title}\n"
+ "- target_audience: {target_audience}\n"
+ "- book_description: {book_description}\n"
+ "- chapter_outline_json: {chapter_outline_json}\n\n"
+ "==============================\n"
+ "الإخراج\n"
+ "==============================\n"
+ "JSON فقط مطابق لـ ChapterPlanningBlock.\n"
+ "لا تضعه داخل List.\n"
+ "لا تُرجع أي Chapters أخرى.\n"
+ "وتأكد أن كل Section يحتوي:\n"
+ "- section_intro_paragraph (نص فعلي)\n"
+ "- section_closing_paragraph (نص فعلي)\n"
+ "- plans (Blueprint فقط)\n"
+ ),
+ expected_output="Strict JSON conforming to ChapterPlanningBlock",
+ output_json=ChapterPlanningBlockDTO,
+ agent=book_planner_agent,
+ async_execution=False,
+ )
+
+ return book_planner_agent, planning_task
diff --git a/agents/books/book_structure.py b/agents/books/book_structure.py
new file mode 100644
index 0000000000000000000000000000000000000000..81d49d77d61aa42f7f106638c938e73a01fea361
--- /dev/null
+++ b/agents/books/book_structure.py
@@ -0,0 +1,401 @@
+# from crewai import Agent, Task
+# import os
+# import json
+# from modules import llm_4m
+# from schemas import BookOutlineOutput
+
+# # ---------------------------------
+# # 2) Book Structure Agent
+# # ---------------------------------
+# def book_structure_agent():
+# model = llm_4m()
+# return Agent(
+# name="SubsectionStructureAgent",
+# role="منظّم محاور فرعية داخل هيكل كتاب جاهز",
+# goal=(
+# "تنظيم وبناء المحاور الفرعية (Subsections) فقط داخل الهيكل المُعطى للكتاب، "
+# "مع الحفاظ التام على أسماء وترتيب الفصول والأقسام كما وردت، "
+# "ودون إنشاء أو إعادة تسمية أي وحدات عليا (Chapters/Sections)، "
+# "ودون كتابة محتوى فعلي. "
+# "المطلوب: محاور فرعية بعناوين جذابة وواضحة وغير تقليدية، تُسهل رحلة القارئ."
+# ),
+# backstory=(
+# "أنت محرر كتب محترف متخصص في تصميم هياكل الكتب بمختلف أنواعها "
+# "(تعليمية، معرفية، تطوير ذات، أعمال، أو غير خيالية). "
+# "تجيد العمل داخل هياكل كتب جاهزة دون تعديلها، "
+# "وتلتزم التزامًا صارمًا بالحفاظ على أسماء الفصول والأقسام وترتيبها كما هي. "
+# "ويقتصر دورك على بناء المحاور الفرعية (Subsections) وتنظيمها منطقيًا داخل كل قسم.\n\n"
+# "تميزك الأساسي: صياغة عناوين محاور فرعية قوية غير جامدة ولا أكاديمية ثقيلة. "
+# "تتجنب التكرار اللفظي، وتبتعد عن الافتتاحيات التقليدية، "
+# "وتقسم الأفكار الكبيرة إلى محاور صغيرة واضحة (فكرة واحدة لكل محور)."
+# ),
+# llm=model,
+# verbose=False,
+# memory=False,
+# allow_delegation=False,
+# )
+
+
+# # ---------------------------------
+# # 3) Task: Generate Book Outline JSON (STRICT)
+# # ---------------------------------
+# def generate_book_outline_task(structure_agent):
+# return Task(
+# name="Generate book outline (NO content writing)",
+# description=(
+# """أنت تبني هيكل كتاب فقط (Outline) من بيانات الإدخال،
+# بما يتناسب مع نوع الكتاب (تعليمي، معرفي، تطوير ذات، أعمال، أو غير خيالي)،
+# مع مراعاة الجمهور المستهدف وطبيعة التجربة القرائية.
+# """
+# """تنبيه صارم:
+# - لا تقم بإنشاء فصول (Chapters) جديدة.
+# - لا تقم بإنشاء أقسام (Sections) جديدة.
+# - لا تغيّر أسماء Chapters أو Sections الواردة في raw_units حرفيًا.
+# - لا تعيد ترتيب الفصول أو الأقسام.
+# - دورك يقتصر حصريًا على:
+# • تنظيم وبناء Subsections داخل كل Section موجود.
+# """
+# "==============================\n"
+# "قواعد إلزامية (معايير إعداد الكتب)\n"
+# "==============================\n"
+# "1) ممنوع كتابة محتوى الكتاب/شرح مطول/أمثلة تفصيلية. أنت تنتج هيكل فقط.\n"
+# "2) الوضوح والبساطة في العناوين واللغة.\n"
+# """3) عدد Subsections يجب أن يكون مرنًا حسب حجم الفكرة داخل Section.
+
+# - الحد الأدنى: 2
+# - الحد الأقصى: 6
+
+# لكن لا تختَر دائمًا الحد الأدنى.
+
+# قاعدة الاختيار:
+# - إذا كان القسم بسيط → 2–3 محاور
+# - إذا كان القسم متوسط → 3–4 محاور
+# - إذا كان القسم غني بالمفاهيم → 4–6 محاور
+
+# اختر العدد الذي يخدم الفكرة وليس الحد الأدنى دائمًا."""
+# "5) منع التكرار: لا تكرر نفس الفكرة بين محاور متجاورة، ولا تكرر نفس الصياغة الافتتاحية.\n"
+# """6) التدرج:
+# - الكتب التعليمية: من الأساسيات إلى التطبيق/التحليل
+# - الكتب غير التعليمية: من التمهيد إلى التعمق ثم الخلاصة/التحول
+# - يجب أن يعكس الترتيب رحلة القارئ الطبيعية
+# """
+# "7) ترابط منطقي بين الأقسام والمحاور (بدون قفزات مفاهيمية).\n\n"
+# "==============================\n"
+# "قواعد إلزامية لصياغة عناوين Subsections (مهم جدًا)\n"
+# "==============================\n"
+# "A) عناوين المحاور الفرعية لازم تكون:\n"
+# " - قصيرة وواضحة (يفضل 2–6 كلمات).\n"
+# " - غير تقليدية/غير جامدة، وتشد القارئ.\n"
+# " - لغة بسيطة مناسبة للجمهور (ابتعد عن الأسلوب الأكاديمي الثقيل).\n"
+# " - فكرة واحدة لكل عنوان.\n"
+# "B) ممنوع تكرار بدايات العناوين أو الحشو اللفظي.\n"
+# " - لا تبدأ عدة محاور بنفس الصيغة مثل: (في ظل...)، (يبرز...)، (من المعروف...)، (يتناول هذا القسم...).\n"
+# "C) تجنب العناوين المركّبة التي تجمع محورين مختلفين في عنوان واحد.\n"
+# " - مثال ممنوع: (تعريف الصمود النفسي وأهميته)\n"
+# " - الصحيح: محور لتعريف المفهوم + محور مستقل للأهمية/الفوائد.\n"
+# "D) تجنب كلمات فضفاضة أو غير دقيقة في العناوين مثل:\n"
+# " - (الرئيسية/الأساسية) إذا كانت لا تضيف معنى.\n"
+# "E) لا تستخدم عناوين تشبه عناوين الأبحاث (توثيق/اقتباسات/أسماء باحثين/سنوات) داخل العناوين.\n"
+# "F) يجوز استخدام أساليب عنوان جذابة حسب نوع القسم:\n"
+# " - سؤال تحفيزي، عبارة قصيرة، أو صياغة عملية (لكن بدون كتابة محتوى).\n\n"
+# """
+# ==============================
+# تقسيم المحاور بطريقة جذابة للقارئ
+# ==============================
+
+# لا تقسّم المحاور بطريقة ميكانيكية.
+
+# بدلًا من تقسيم عشوائي، استخدم أحد أنماط التقسيم التالية حسب طبيعة الموضوع:
+
+# - المشكلة → الفهم → الحل
+# - المفهوم → المكونات → التطبيق
+# - الفكرة → التحديات → الاستراتيجيات
+# - الأساسيات → الأدوات → الاستخدام
+# - الأخطاء → التصحيح → التحسين
+
+# الهدف:
+# أن يشعر القارئ أن كل Section يمثل رحلة فكرية وليس مجرد عناوين متفرقة.
+# """
+# """
+# ==============================
+# توزيع الصفحات (مهم جدًا)
+# ==============================
+
+# إذا تم تمرير target_total_pages:
+
+# 1) احسب متوسط صفحات الفصل:
+
+# avg_chapter_pages = target_total_pages ÷ عدد الفصول
+
+# مثال:
+# كتاب 100 صفحة
+# 4 فصول
+# → متوسط الفصل ≈ 25 صفحة
+
+# 2) وزّع الصفحات على الفصول بشكل قريب من المتوسط
+# لكن يمكن أن يختلف ±20% حسب عمق الفصل.
+
+# 3) داخل كل فصل:
+# قسّم الصفحات على Sections بشكل منطقي.
+
+# 4) داخل كل Section:
+# قسّم الصفحات على Subsections بحيث:
+
+# - المحور القصير: 1–2 صفحات
+# - المحور المتوسط: 2–3 صفحات
+# - المحور المتعمق: 3–5 صفحات
+
+# 5) تحقق إلزامي:
+
+# مجموع est_pages لكل Subsections
+# = target_total_pages بالضبط
+
+# إذا لم يساوِ:
+# قم بتعديل التوزيع حتى يتطابق المجموع.
+# """
+# """
+# ==============================
+# مراعاة حجم الكتاب
+# ==============================
+
+# لا تقرر عدد المحاور أولًا.
+
+# ابدأ بتقدير حجم الكتاب:
+
+# - كتاب 60–100 صفحة → محاور أقل وشرح مركز
+# - كتاب 100–180 صفحة → توازن بين عدد المحاور وعمق الشرح
+# - كتاب 180+ صفحة → محاور أكثر وتفصيل أكبر
+
+# القاعدة الأساسية:
+
+# عدد الصفحات هو الذي يحدد عدد المحاور
+# وليس العكس.
+# """
+# "==============================\n"
+# "الحفاظ على الأسماء\n"
+# "==============================\n"
+# """- استخدم عناوين Chapters وSections كما هي حرفيًا من raw_units.
+# - يُمنع إعادة الصياغة أو التحسين اللغوي لعناوين Chapters/Sections.
+# - التعديل/التحسين مسموح فقط داخل Subsections التي تنشئها.
+# """
+# "==============================\n"
+# "المدخلات\n"
+# "==============================\n"
+# "- book_title: {book_title}\n"
+# "- target_audience: {target_audience}\n"
+# "- book_description: {book_description}\n"
+# "- learning_outcomes: {learning_outcomes}\n"
+# "- raw_units: {raw_units}\n"
+# "- target_total_pages (optional): {target_total_pages}\n"
+# "- example_reference (optional): {example_reference}\n\n"
+# """ملاحظة مهمة:
+# raw_units تمثل الهيكل النهائي للفصول والأقسام.
+# يُمنع تعديل أو إعادة تسمية أي Unit أو Topic.
+# Subsections فقط هي التي يتم إنشاؤها وتنظيمها.
+# """
+# "==============================\n"
+# "مطلوب الإخراج (JSON صارم)\n"
+# "==============================\n"
+# "أخرج JSON فقط مطابق لـ BookOutlineOutput وبنفس أسماء الحقول:\n"
+# "{\n"
+# ' "book_title": "...",\n'
+# ' "target_audience": "...",\n'
+# ' "book_description": "...",\n'
+# ' "chapters": [\n'
+# " {\n"
+# ' "chapter_title": "...",\n'
+# ' "outcome": "...",\n'
+# ' "sections": [\n'
+# " {\n"
+# ' "title": "...",\n'
+# ' "overview": "...",\n'
+# ' "subsections": [\n'
+# " {\n"
+# ' "title": "...",\n'
+# ' "purpose": "...",\n'
+# ' "suggested_queries": ["..."],\n'
+# ' "difficulty": "basic|intermediate|advanced",\n'
+# ' "est_pages": 1\n'
+# " }\n"
+# " ]\n"
+# " }\n"
+# " ]\n"
+# " }\n"
+# " ],\n"
+# ' "outline_notes": "..."\n'
+# ' "total_pages": 50\n'
+# "}\n"
+# "==============================\n"
+# "تحقق إلزامي قبل الإخراج\n"
+# "==============================\n"
+# """
+# قبل إخراج الـ JSON النهائي، راجع ما يلي بدقة:
+# - كل Chapter يحتوي 2–6 Sections
+# - كل Section يحتوي على 2–6 Subsections (لا أقل من 2 نهائيًا)
+# - إذا وجدت Section تحتوي فكرة واحدة فقط:
+# → قم بتقسيمها إلى محورين منطقيين مختلفين
+# - راجع عناوين Subsections:
+# → لا تكرار في بدايات العناوين
+# → لا عناوين جامدة/تقليدية
+# → لا دمج (تعريف + أهمية) في عنوان واحد
+
+# 1) اجمع جميع est_pages في Subsections.
+# 2) تحقق أن المجموع = target_total_pages.
+
+# إذا لم يتطابق:
+
+# قم بإعادة توزيع est_pages حتى يصبح المجموع مطابقًا تمامًا.
+# - لا تخرج JSON حتى تتأكد أن جميع القيود محققة
+# - أي مخالفة ستُعد إخراجًا غير صالح
+# """
+# ),
+# expected_output="Strict JSON matching BookOutlineOutput schema (NO extra keys).",
+# output_json=BookOutlineOutput,
+# agent=structure_agent,
+# async_execution=False,
+# )
+from crewai import Agent, Task
+from modules import llm_4m
+from schemas import BookOutlineOutput
+
+
+# ---------------------------------------------------
+# Agent: Book Structure Designer
+# ---------------------------------------------------
+def book_structure_agent():
+ model = llm_4m()
+
+ return Agent(
+ name="BookStructureDesigner",
+ role="مصمم هياكل كتب احترافية",
+ goal=(
+ "تصميم محاور فرعية جذابة داخل الهيكل المعطى للكتاب "
+ "مع الحفاظ الكامل على أسماء الفصول والأقسام كما هي "
+ "ودون تعديلها أو إعادة ترتيبها."
+ ),
+ backstory=(
+ "أنت محرر كتب محترف تعمل مع دور نشر كبيرة. "
+ "مهمتك تصميم المحاور الفرعية (Subsections) التي تجعل القارئ "
+ "يتنقل داخل القسم بسهولة وبفضول معرفي.\n\n"
+ "لا تكتب محتوى الكتاب. دورك هو تصميم الهيكل فقط.\n\n"
+ "تميزك الأساسي:\n"
+ "- صياغة عناوين جذابة وليست أكاديمية ثقيلة\n"
+ "- تقسيم الفكرة الكبيرة إلى محاور واضحة\n"
+ "- كل عنوان يمثل فكرة واحدة فقط\n"
+ "- تجنب التكرار والجمود في العناوين\n"
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+
+# ---------------------------------------------------
+# Task: Generate Book Outline
+# ---------------------------------------------------
+def generate_book_outline_task(structure_agent):
+
+ return Task(
+ name="Generate book outline",
+ description=(
+ "مهمتك بناء هيكل كتاب (Book Outline) فقط.\n"
+ "لا تكتب محتوى فعلي للكتاب.\n\n"
+ "=========================\n"
+ "القواعد الأساسية\n"
+ "=========================\n"
+ "1) لا تقم بإنشاء Chapters جديدة\n"
+ "2) لا تقم بإنشاء Sections جديدة\n"
+ "3) لا تغيّر أسماء Chapters أو Sections\n"
+ "4) لا تعيد ترتيب الهيكل\n"
+ "5) دورك فقط إنشاء Subsections داخل كل Section\n\n"
+ "=========================\n"
+ "قواعد إنشاء Subsections\n"
+ "=========================\n"
+ "- كل Section يجب أن يحتوي 2 إلى 6 Subsections\n"
+ "- كل Subsection يمثل فكرة واحدة واضحة\n"
+ "- رتب المحاور بشكل منطقي بحيث تشكل رحلة للقارئ\n"
+ "أنماط تقسيم مناسبة:\n"
+ "- المفهوم → الفهم → التطبيق\n"
+ "- المشكلة → التحليل → الحل\n"
+ "- الفكرة → التحديات → الاستراتيجيات\n"
+ "- الأساسيات → الأدوات → الاستخدام\n\n"
+ "=========================\n"
+ "قواعد صياغة العناوين\n"
+ "=========================\n"
+ "العناوين يجب أن تكون:\n"
+ "- قصيرة (2 إلى 6 كلمات)\n"
+ "- جذابة وسهلة القراءة\n"
+ "- غير أكاديمية ثقيلة\n"
+ "- فكرة واحدة لكل عنوان\n"
+ "تجنب:\n"
+ "- تعريف + أهمية في نفس العنوان\n"
+ "- تكرار نفس بداية العنوان\n"
+ "- العناوين الجامدة\n\n"
+ "أمثلة لعناوين جيدة:\n"
+ "- لماذا تفشل الخطط؟\n"
+ "- لحظة اكتشاف المشكلة\n"
+ "- الفكرة التي تغير كل شيء\n"
+ "- عندما يتحول الضغط إلى فرصة\n\n"
+ "=========================\n"
+ "المدخلات\n"
+ "=========================\n"
+ "book_title: {book_title}\n"
+ "target_audience: {target_audience}\n"
+ "book_description: {book_description}\n"
+ "learning_outcomes: {learning_outcomes}\n"
+ "raw_units: {raw_units}\n"
+ "target_total_pages: {target_total_pages}\n\n"
+ "example_reference (استلهم منه أسلوب العناوين فقط):\n"
+ "{example_reference}\n\n"
+ "raw_units تمثل الهيكل النهائي للفصول والأقسام.\n"
+ "يُمنع تعديلها.\n"
+ "قم فقط بإضافة Subsections داخل كل Section.\n\n"
+ "=========================\n"
+ "توزيع الصفحات\n"
+ "=========================\n"
+ "إذا تم تمرير target_total_pages:\n"
+ "- وزع الصفحات على Subsections\n"
+ "- المحور القصير: 1-2 صفحات\n"
+ "- المحور المتوسط: 2-3 صفحات\n"
+ "- المحور العميق: 3-5 صفحات\n"
+ "مجموع الصفحات يجب أن يساوي target_total_pages.\n\n"
+ "=========================\n"
+ "الإخراج المطلوب\n"
+ "=========================\n"
+ "أخرج JSON فقط مطابق لـ BookOutlineOutput.\n"
+ "{\n"
+ ' "book_title": "...",\n'
+ ' "target_audience": "...",\n'
+ ' "book_description": "...",\n'
+ ' "chapters": [\n'
+ " {\n"
+ ' "chapter_title": "...",\n'
+ ' "outcome": "...",\n'
+ ' "sections": [\n'
+ " {\n"
+ ' "title": "...",\n'
+ ' "overview": "...",\n'
+ ' "subsections": [\n'
+ " {\n"
+ ' "title": "...",\n'
+ ' "purpose": "...",\n'
+ ' "suggested_queries": ["..."],\n'
+ ' "difficulty": "basic|intermediate|advanced",\n'
+ ' "est_pages": 1\n'
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ],\n"
+ ' "outline_notes": "...",\n'
+ ' "total_pages": 50\n'
+ "}\n\n"
+ "لا تضف أي نص خارج JSON."
+ ),
+ expected_output="Strict JSON matching BookOutlineOutput schema",
+ output_json=BookOutlineOutput,
+ agent=structure_agent,
+ async_execution=False,
+ )
diff --git a/agents/books/enrichment.py b/agents/books/enrichment.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbd4101e0be5e7e539a1ef2bce9682ddb3a8f5a6
--- /dev/null
+++ b/agents/books/enrichment.py
@@ -0,0 +1,140 @@
+from crewai import Agent, Task, Crew, Process
+import os
+import json
+from modules import llm_open_grok
+from schemas.books.enrichment import EnrichedContentOutput
+def create_enrichment_agent():
+ model=llm_open_grok()
+ return Agent(
+ name="ArabicNarrativeEnrichmentAgent",
+ role="Arabic Cognitive Content Enricher",
+ goal=(
+ "إثراء المحتوى العربي الأكاديمي بفواصل معرفية إنسانية عميقة، "
+ "تُدمج داخل النص بسلاسة دون كسر أسلوب سرد المحتوى. "
+ "تعمل هذه الفواصل على تعميق الفهم، وتحفيز التفكير، وربط المفاهيم النظرية بالواقع الإنساني، "
+ "تشمل: اقتباسات ملهمة، قصص واقعية، دراسات حالة، إحصائيات معرفية، "
+ "ونصائح عملية - كلها مدمجة بشكل طبيعي وذكي داخل المحتوى "
+ "يجب أن تبدو الإضافات كأنها من بنية النص الأصلية، "
+ "لا كإضافات خارجية أو مولدة آليًا."
+ ),
+ backstory=(
+ "أنت محرر معرفي عربي متخصص في صناعة المحتوى العميق غير المباشر. "
+ "عملك الأساسي هو تحويل النصوص الأكاديمية الجافة إلى نصوص حيّة نابضة بالفهم الإنساني، "
+ "من خلال إدخال فواصل تحليلية ذكية داخل السياق، "
+ "تشبه أسلوب كبار المفكرين العرب في الربط بين النظرية والواقع. "
+ "تمتلك خبرة واسعة في علم النفس التربوي، والقيادة، والتنمية البشرية، "
+ "وتجيد توظيف الأمثلة الواقعية والتاريخية دون تهويل أو إنشائية. "
+ "أسلوبك يشبه الكاتب البشري الخبير الذي يكتب بهدوء وعمق، "
+ "لا يستخدم لغة دعائية أو تحفيزية سطحية، "
+ "تحرص على أن تكون كل فاصلة ذات قيمة حقيقية، "
+ "تتجنب الاقتباسات المكررة أو القصص المستهلكة، "
+ "ولا يخرج عن روح النص الأصلي. "
+ "كل إضافة تقوم بها يجب أن تخدم الفكرة المركزية للمحتوى، "
+ "وتُشعر القارئ أنه اكتسب بعدًا فكريًا جديدًا، لا مجرد قصة جانبية."
+ ),
+ constraints=(
+ "1) يمنع منعًا باتًا استخدام لغة تحفيزية مباشرة أو شعاراتية.\n"
+ "2) يمنع استخدام عبارات مثل: في الختام، لا شك أن، من المهم جدًا.\n"
+ "3) كل فاصل يجب أن يخدم فكرة محددة سبقتْه مباشرة.\n"
+ "4) لا يُسمح بتكرار نفس الفكرة بصيغة أخرى.\n"
+ "5) الفاصل يجب أن يضيف بعدًا تطبيقيًا أو إنسانيًا جديدًا.\n"
+ "6) الأسلوب لغوي بشري هادئ، تحليلي، غير متكلف.\n"
+ "7) يمنع استخدام أسلوب الوعظ أو الخطابة.\n"
+ "8) يجب أن يبدو الفاصل كامتداد طبيعي للنص، لا كفقرة دخيلة.\n"
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+ )
+
+
+def create_enrichment_task(enrichment_agent):
+ return Task(
+ description=(
+ "يتم تزويدك بمحتوى عربي أكاديمي موثوق مستخرج من كتاب\n"
+ "ومطلوب منك إثراؤه بفواصل إبداعية مبتكرة تجعله أكثر جاذبية وتأثيراً."
+ "دون إعادة كتابة المحتوى الأصلي.\n\n"
+ "=================================================\n"
+ " قواعد التنفيذ\n"
+ "=================================================\n"
+ " - الفاصلة يجب أن تأتي في السياق المناسب تماماً\n"
+ " - لا تقطع تسلسل الأفكار\n"
+ " - تُضاف بعد شرح المفهوم، ليس قبله\n"
+ " - تكون كتأكيد أو إثراء لما سبق\n\n"
+ "2) **الظهور المميز**:\n"
+ " - الاقتباسات: بين علامات تنصيص وفي سطر منفصل\n"
+ " - القصص: لها عنوان فرعي مميز بخط عريض\n"
+ " - مسموح بوجود فاصلتين وراء بعض اذا كانت لهم اضافة مميزه وقويه"
+ " - مسافة بصرية قبل وبعد كل فاصلة\n\n"
+ "3) **التنوع**:\n"
+ " - لا تستخدم نفس النوع مرتين متتاليتين\n"
+ " - نوّع بين القصص والاقتباسات والإحصائيات وباقي انواع الفصلات مسموح ايضا بالابتكار\n"
+ "4) **الأصالة**:\n"
+ " - تجنب الاقتباسات المكررة والمستهلكة\n"
+ " - كن مبدعاً في الصياغة\n\n"
+ "5) **الارتباط القوي بالموضوع**:\n"
+ " - كل فاصلة يجب أن تخدم المحور مباشرة\n"
+ # " - لا مجال للحشو أو الفواصل العامة\n"
+ " - القصة أو الاقتباس يجب أن يعمق الفهم\n\n"
+ "=================================================\n"
+ " شكل الفواصل\n"
+ "=================================================\n"
+ "الفاصل يجب أن يبدو كاستطراد ذكي من الكاتب نفسه:\n"
+ "1️⃣ **اقتباسات ملهمة ومعرفية**\n"
+ " - يمكن أن تكون:\n"
+ " * حكمة عربية أصيلة\n"
+ " * اقتباس من خبير أو مفكر معروف\n"
+ " * إحصائية مدهشة\n"
+ " * حقيقة علمية مثيرة\n"
+ " مثال: {ref1}\n\n"
+ "2️⃣ **قصص واقعية ملهمة**\n"
+ " - قصة قصيرة (3-6 فقرات)\n"
+ " - لها عنوان فرعي واضح\n"
+ " - تحكي عن تجربة حقيقية لشخص أو مؤسسة معروفة\n"
+ " - مثال: {ref2}\n\n"
+ "3️⃣ **دراسات حالة قصيرة**\n"
+ " - مثال تطبيقي من واقع الحياة\n"
+ " - يمكن أن تكون من:\n"
+ " * شركات ناجحة\n"
+ " * تجارب تعليمية\n"
+ " * مواقف اجتماعية\n"
+ " * أبحاث علمية مبسطة\n"
+ " - مثال: {ref3}\n\n"
+ "4️⃣ **نصائح عملية مميزة**\n"
+ " - نقاط إرشادية سريعة\n"
+ " - يمكن وضعها في إطار مميز\n"
+ # " - مثال: {ref4}\n\n"
+ "5️⃣ **إضاءات معرفية**\n"
+ " - معلومة مثيرة أو غير متوقعة\n"
+ " - حقيقة علمية مدهشة\n"
+ " - إحصائية مفاجئة\n\n"
+ " - مثال: {ref5}\n\n"
+ "يجب ذكر المصادر أو المرجع لكل إضافة بشكل واضح في نهاية الاضاءة، مع تضمين اسم المصدر وتاريخ الوصول إذا كان من الإنترنت.\n\n"
+ "=================================================\n"
+ "INPUT\n"
+ "=================================================\n"
+ "{generated_content}\n\n"
+ "audiance: {target_audiance}"
+ "=================================================\n"
+ "OUTPUT\n"
+ "=================================================\n"
+ "أعد نفس النص بعد إدخال الفواصل الإثرائية داخله، "
+ "مع الحفاظ الكامل على بنية المحتوى الأصلية."
+ ),
+ agent=enrichment_agent,
+ expected_output="A valid JSON following EnrichedContentOutput schema",
+ output_json=EnrichedContentOutput,
+ # output_file=os.path.join(output_dir, "enriched_content.json"),
+ )
+
+def make_enrichment_crew():
+ enrichment_agent = create_enrichment_agent()
+ enrichment_task = create_enrichment_task(enrichment_agent)
+
+ return Crew(
+ agents=[enrichment_agent],
+ tasks=[enrichment_task],
+ process=Process.sequential,
+ verbose=False
+ )
diff --git a/agents/books/intro_plan.py b/agents/books/intro_plan.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c18f19b5d440682fbf4f7dd14136dbe7d8c99db
--- /dev/null
+++ b/agents/books/intro_plan.py
@@ -0,0 +1,51 @@
+from crewai import Agent, Task
+import os
+import json
+from modules import llm_g
+from schemas import IntroPlan
+
+def intro_style_planner():
+ model = llm_g()
+ return Agent(
+ role="Book Introduction Style Planner",
+ goal=(
+ "Design the MOST SUITABLE and VARIED introduction style for each chapter in a book. "
+ "You must ensure stylistic diversity across chapters and avoid repetition of intro approaches."
+ ),
+ backstory=(
+ "You are a senior book editor and literary architect. "
+ "You design how each chapter should open so the reader experiences emotional rhythm and variety. "
+ "You avoid monotony by alternating narrative, reflective, conceptual, and atmospheric openings. "
+ "You NEVER assign the same intro_function or tone repeatedly across consecutive chapters."
+ ),
+ llm=model,
+ verbose=True,
+ memory=False,
+)
+
+def intro_style_planner_task(intro_style_planner_agent):
+ return Task(
+ description=(
+ "You are given a FULL BOOK PLAN containing ALL chapters.\n\n"
+ "Your job is NOT to analyze text.\n"
+ "Your job is to DESIGN the most suitable introduction style for EACH chapter.\n\n"
+ "### Goals:\n"
+ "1) Each chapter must receive a StyleOutput profile.\n"
+ "2) Styles MUST fit the chapter topic and emotional intent.\n"
+ "3) Styles MUST NOT repeat across chapters.\n"
+ "4) Consecutive chapters MUST NOT share the same intro_function.\n"
+ "5) The book must feel rhythmically varied (narrative → reflective → conceptual → atmospheric → etc).\n\n"
+ "### Diversity Rules (HARD CONSTRAINTS):\n"
+ "- Do NOT repeat the same intro_function more than once.\n"
+ "- Do NOT reuse identical tone or sentence_structure in adjacent chapters.\n"
+ "- Vary opening strategies: story, scene, question, metaphor, reflection, contrast.\n\n"
+ "### Output:\n"
+ "Return ONE JSON object for the whole book using IntroStylePlan schema.\n\n"
+ "Input book chapters:\n"
+ "{book_plan}"
+ ),
+ agent=intro_style_planner_agent,
+ expected_output="A valid JSON following IntroPlan schema with inferred intro-writing rules",
+ output_json=IntroPlan,
+ # output_file=os.path.join(output_dir, "style_output_2.json"),
+ )
diff --git a/agents/books/queries_agent.py b/agents/books/queries_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..6afb1748c582757b884da85cf7f37211224b86f9
--- /dev/null
+++ b/agents/books/queries_agent.py
@@ -0,0 +1,232 @@
+# from crewai import Agent, Task
+# import os
+# import json
+# from modules import llm_4m
+# from schemas import BookOutlineWithQueries
+
+# def query_agent():
+# model = llm_4m()
+# return Agent(
+# name="BookSourceQueryAgent",
+# role="Generate production-ready source search queries for each subsection",
+# goal=(
+# "For each subsection in the book outline JSON, generate 2–3 short, precise search queries "
+# "that are likely to retrieve trustworthy sources suitable for APA 7 citations. "
+# "Sources may include academic papers, theses, institutional PDFs, and high-quality professional books."
+# ),
+# backstory=(
+# "You are a research strategist who designs search queries optimized for sourcing credible references "
+# "usable for in-text citations and reference lists. You know how to bias search results toward PDFs, "
+# "books, theses, and institutional publications and avoid blogs, social media, marketing pages, and courses."
+# ),
+# verbose=False,
+# llm=model,
+# )
+
+
+# def query_task(query_agent):
+# return Task(
+# name="Generate academic/professional source queries per subsection",
+# description=(
+# "You will receive a structured BOOK JSON (chapters → sections → subsections). "
+# # "For EACH subsection, generate 2–3 concise and diverse search queries in Arabic and/or English.\n\n"
+# "For EACH subsection, generate 2–3 concise and diverse search queries in Arabic.\n\n"
+# "=================================================\n"
+# "📌 MANDATORY QUERY RULES (DO NOT VIOLATE)\n"
+# "=================================================\n"
+# "1) Each query MUST clearly target credible sources such as:\n"
+# " - Books (professional or academic)\n"
+# " - PDF documents\n"
+# " - Research papers / academic studies\n"
+# " - Theses / dissertations\n"
+# " - Institutional publications (e.g., APA, WHO, universities)\n\n"
+# "2) Prefer adding intent keywords when helpful:\n"
+# " - Arabic: (PDF، كتاب، دراسة، بحث علمي، رسالة ماجستير)\n"
+# # " - English: (PDF, book, research paper, academic study, thesis)\n\n"
+# "3) Avoid queries that could return:\n"
+# " - Blogs\n"
+# " - Online courses\n"
+# " - Marketing articles\n"
+# " - Social media content\n"
+# " - Wikipedia-like summaries\n\n"
+# "4) Queries must be:\n"
+# " - Short\n"
+# " - Specific\n"
+# " - Directly related to the subsection topic\n\n"
+# "5) Do NOT repeat the same phrasing across queries. Each query must use a different angle:\n"
+# " Example angles: definition + theory, measurement scale + instrument, meta-analysis + review, book + author.\n\n"
+# "6) At least ONE query per subsection MUST explicitly target BOOKS.\n\n"
+# "=================================================\n"
+# "📌 INPUT\n"
+# "=================================================\n"
+# "Book JSON:\n"
+# "{book}\n\n"
+# "=================================================\n"
+# "📌 OUTPUT REQUIREMENTS\n"
+# "=================================================\n"
+# "Return ONLY a valid JSON that keeps the SAME input structure. \n"
+# "=========================\n"
+# "الإخراج المطلوب\n"
+# "=========================\n"
+# "أخرج JSON فقط مطابق لـ BookOutlineWithQueries.\n"
+# "{\n"
+# ' "book_title": "...",\n'
+# ' "target_audience": "...",\n'
+# ' "book_description": "...",\n'
+# ' "chapters": [\n'
+# " {\n"
+# ' "chapter_title": "...",\n'
+# ' "outcome": "...",\n'
+# ' "sections": [\n'
+# " {\n"
+# ' "title": "...",\n'
+# ' "overview": "...",\n'
+# ' "subsections": [\n'
+# " {\n"
+# ' "title": "...",\n'
+# ' "purpose": "...",\n'
+# ' "suggested_queries": ["..."],\n'
+# ' "academic_queries": ["..."],\n'
+# ' "difficulty": "basic|intermediate|advanced",\n'
+# ' "est_pages": 1\n'
+# " }\n"
+# " ]\n"
+# " }\n"
+# " ]\n"
+# " }\n"
+# " ],\n"
+# ' "outline_notes": "...",\n'
+# ' "total_pages": 50\n'
+# "}\n\n"
+# "For each subsection, ADD a new field exactly named: academic_queries (2–3 items).\n"
+# "Do NOT remove or rename any existing fields.\n"
+# "Do NOT add explanations, comments, or extra text."
+# "Follow the same structure of BookOutlineWithQueries Schema"
+# "Return ONLY ONE JSON object."
+# "Do NOT return multiple JSON objects."
+# "Do NOT use tool calls."
+# "Do NOT wrap the output."
+# ),
+# expected_output="A valid JSON following BookOutlineWithQueries schema",
+# output_json=BookOutlineWithQueries,
+# # output_file="book_with_academic_queries.json",
+# agent=query_agent,
+# )
+
+from crewai import Agent, Task
+import os
+import json
+from schemas.books.queries_schema import QueriesOutput
+from modules import llm_4m
+
+
+
+# ==========================================
+# Agent
+# ==========================================
+
+
+def query_agent():
+ model = llm_4m()
+
+ return Agent(
+ name="BookSourceQueryAgent",
+ role="Academic Search Query Generator",
+ goal=(
+ "Generate three high-quality academic search queries for each subsection "
+ "in order to retrieve credible sources suitable for APA 7 citations."
+ ),
+ backstory=(
+ "You are a professional research strategist specialized in designing "
+ "search queries that retrieve high-quality academic sources such as:\n"
+ "- scholarly books\n"
+ "- research papers\n"
+ "- theses and dissertations\n"
+ "- institutional publications\n"
+ "- scientific PDFs\n\n"
+ "You avoid low-quality sources such as blogs, marketing pages, "
+ "courses, social media posts, and generic summaries."
+ ),
+ verbose=False,
+ llm=model,
+ )
+
+
+# ==========================================
+# Task
+# ==========================================
+
+
+def query_task(query_agent):
+ return Task(
+ name="Generate academic queries per subsection",
+ description=(
+ "You will receive a BOOK JSON that contains a hierarchy:\n"
+ "chapters → sections → subsections.\n\n"
+ "Your job is to generate academic search queries for EACH subsection.\n\n"
+ "=================================================\n"
+ "MANDATORY RULES\n"
+ "=================================================\n"
+ "1. For EACH subsection generate EXACTLY 3 queries.\n\n"
+ "2. Queries must target credible sources such as:\n"
+ " - Academic books\n"
+ " - Research papers\n"
+ " - Theses / dissertations\n"
+ " - Institutional publications\n"
+ " - Scientific PDF documents\n\n"
+ "3. Queries should be written primarily in Arabic.\n\n"
+ "4. Queries must be:\n"
+ " - Short\n"
+ " - Specific\n"
+ " - Directly related to the subsection topic\n\n"
+ "5. Prefer adding academic intent keywords when useful:\n"
+ " (PDF، كتاب، دراسة، بحث علمي، رسالة ماجستير)\n\n"
+ "6. At least ONE query per subsection MUST target BOOKS.\n\n"
+ "7. Avoid queries likely to return:\n"
+ " - Blogs\n"
+ " - Online courses\n"
+ " - Marketing articles\n"
+ " - Social media\n"
+ " - Wikipedia-like summaries\n\n"
+ "=================================================\n"
+ "INPUT\n"
+ "=================================================\n"
+ "Book JSON:\n"
+ "{book}\n\n"
+ "=================================================\n"
+ "OUTPUT FORMAT (STRICT)\n"
+ "=================================================\n"
+ "Return ONLY a JSON object with the following structure:\n\n"
+ "{\n"
+ ' "queries": [\n'
+ " {\n"
+ ' "subsection": "Subsection Title",\n'
+ ' "queries": [\n'
+ ' "query 1",\n'
+ ' "query 2",\n'
+ ' "query 3"\n'
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n\n"
+ "=================================================\n"
+ "CRITICAL OUTPUT RULES\n"
+ "=================================================\n"
+ "• Include EVERY subsection from the input.\n"
+ "• The number of objects in 'queries' MUST equal the number of subsections.\n"
+ "• Each subsection MUST contain EXACTLY 3 queries.\n"
+ "• Preserve the original subsection titles exactly.\n"
+ "• Do NOT include chapters or sections in the output.\n"
+ "• Do NOT add explanations, comments, or text outside JSON.\n"
+ "• Output must be valid JSON only."
+ ),
+ expected_output=(
+ "{"
+ '"queries":['
+ '{"subsection":"Example subsection","queries":["q1","q2","q3"]}'
+ "]"
+ "}"
+ ),
+ agent=query_agent,
+ output_json=QueriesOutput,
+ )
diff --git a/agents/books/reference_lang.py b/agents/books/reference_lang.py
new file mode 100644
index 0000000000000000000000000000000000000000..5bf43432d57178338c41d39f5f476b6c17cab386
--- /dev/null
+++ b/agents/books/reference_lang.py
@@ -0,0 +1,252 @@
+from langchain.messages import SystemMessage, HumanMessage
+from modules import model_open_router
+import os
+import re
+
+# ✅ System Prompt optimized (بديل الدليل الضخم)
+SYSTEM_PROMPT = """
+You are an expert in APA 7th edition reference formatting.
+
+STRICT RULES:
+
+- Output ONLY the formatted reference (no explanations).
+- Each reference must be on a new line.
+- Do NOT invent missing data.
+- Use (n.d.) if date is missing.
+- Keep original language (Arabic stays Arabic, English stays English).
+
+GENERAL FORMAT RULES:
+
+1. Author:
+ - Format: Last name, Initial(s).
+ - Multiple authors:
+ - 2 authors: Author1, A. A., & Author2, B. B.
+ - 3+ authors: Author1, A. A., et al.
+
+2. Year:
+ - Must be in parentheses: (2023)
+
+3. Title:
+ - Sentence case (only first word capitalized in English)
+ - Italicize book/journal titles conceptually
+
+4. Books:
+ Author. (Year). Title (Edition). City: Publisher.
+
+5. Journal articles:
+ Author. (Year). Title. Journal Name, Volume(Issue), pages.
+
+6. Conference papers:
+ Author. (Year). Title. Conference Name, Location, Date.
+
+7. Theses:
+ Author. (Year). Title [Thesis type], Institution.
+
+8. Websites:
+ - With author:
+ Author. (Year). Title. URL
+ - Without author:
+ Title. (Year). URL
+
+9. Arabic references:
+ - Keep Arabic format
+ - Use same structure:
+ المؤلف. (السنة). العنوان. المدينة: الناشر.
+
+10. Page numbers:
+ - Use pp. for English
+ - Use ص for Arabic
+
+11. Missing data:
+ - Use (n.d.)
+ - Use [Missing Info] only if critical
+
+12. Fix:
+ - spelling
+ - punctuation
+ - ordering
+
+OUTPUT:
+- Clean APA formatted references only
+- No bullets
+- No numbering
+"""
+
+
+# ✅ تحسين: batching أصغر + fallback
+def normalize_references_batch(refs_list, model,batch_size=2):
+ batches = []
+
+ for i in range(0, len(refs_list), batch_size):
+ chunk = refs_list[i : i + batch_size]
+ batches.append("\n".join(chunk))
+
+ results = []
+
+ for batch in batches:
+ try:
+ messages = [
+ SystemMessage(content=SYSTEM_PROMPT),
+ HumanMessage(content=f"Format in APA 7:\n{batch}"),
+ ]
+
+ response = model.invoke(messages)
+
+ formatted = [
+ line.strip() for line in response.content.split("\n") if line.strip()
+ ]
+
+ results.extend(formatted)
+
+ except Exception as e:
+ print(f"Error in batch: {e}")
+
+ # fallback: رجعهم زي ما هم
+ results.extend(batch.split("\n"))
+
+ return results
+
+
+# ✅ استخراج المراجع
+def extract_references(book_json):
+ refs = []
+
+ for chapter in book_json.get("chapters", []):
+ for section in chapter.get("sections", []):
+ for plan in section.get("plans", {}).values():
+ for chunk in plan.get("rag_context", {}).get("chunks", []):
+ ref = chunk.get("reference_apa")
+ if ref:
+ refs.append(ref)
+
+ book_name = book_json.get("book_title", "")
+
+ return refs, book_name
+
+
+# ✅ إزالة التكرار
+def remove_duplicates(refs):
+ return list(dict.fromkeys(refs))
+
+
+# ✅ HTML cleaner
+def save_refs_to_html(refs_list, book_name):
+ """
+ تحويل قائمة المراجع إلى ملف HTML منسق أكاديمياً مع اسم الكتاب
+ """
+ html_content = f"""
+
+
+
+
+
+ قائمة المراجع - APA 7th Edition
+
+
+
+
+
{book_name}
+
قائمة المراجع (APA 7th Edition)
+
+ """
+
+ for ref in refs_list:
+ import re
+
+ url_pattern = r"(https?://\S+)"
+ formatted_ref = re.sub(
+ url_pattern, r'
\1', ref
+ )
+
+ html_content += f'- {formatted_ref}
\n'
+
+ html_content += """
+
+
+
+
+ """
+
+ return html_content
+
+
+# ✅ Main pipeline
+def run_references(book_json):
+ refs, book_name = extract_references(book_json)
+ print(f"Extracted: {len(refs)}")
+
+ refs = remove_duplicates(refs)
+ print(f"Unique: {len(refs)}")
+
+ # ✅ Model (يفضل موديل أسرع)
+ model = model_open_router()
+ fixed = normalize_references_batch(refs, model)
+ print(f"Formatted: {len(fixed)}")
+
+ html = save_refs_to_html(fixed, book_name)
+
+ return html
diff --git a/agents/books/units_intro.py b/agents/books/units_intro.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8f44aaa2b7d13071bf729e7e26672d7027f0f91
--- /dev/null
+++ b/agents/books/units_intro.py
@@ -0,0 +1,457 @@
+from crewai import Agent, Task
+import os
+import json
+from modules import llm_open_grok, intro_reference1
+from schemas import ChapterIntro
+
+def intro_generator():
+ model = llm_open_grok()
+ return Agent(
+ role="Metadata-Driven Chapter Introduction Writer",
+
+ goal=(
+ "Write a stylistically precise and pedagogically aligned introduction "
+ "for chapter using ONLY the provided metadata and intro style. "
+ "The introduction must feel native to the book and strictly follow "
+ "the chapter’s declared structure, scope, and writing profile."
+ ),
+ backstory=(
+
+ "=============================\n"
+ "CORE IDENTITY\n"
+ "=============================\n"
+ "You are a professional Arabic book author.\n"
+ "You write natural, fluid, elegant prose.\n"
+ "You NEVER sound robotic, or template-based.\n"
+ "You NEVER describe what the chapter will do.\n"
+
+
+ "=============================\n"
+ "LAYER 1 — HARD CONSTRAINTS (CANNOT BE VIOLATED)\n"
+ "=============================\n"
+
+ "❌ NEVER start with a definition.\n"
+ "❌ NEVER summarize the chapter structure.\n"
+ "❌ NEVER list components or sections.\n"
+ "❌ NEVER say: هذا الفصل يتناول / يستعرض / يقدّم / يناقش\n"
+ "❌ NEVER mention audience (طلاب، قارئ، متدرب، موظف...)\n"
+ "❌ NEVER use research claims without attribution.\n"
+ "❌ NEVER use research terminology.\n"
+ "❌ NEVER use direct imagination commands:\n"
+ "تخيّل، تخيّلي، تخيّلوا، لنتخيّل، دعنا نتخيّل\n"
+ "If needed:\n"
+ '→ Describe the scene as if already unfolding\n'
+ '→ Use implicit cinematic narration, not commands\n\n'
+
+ "FORBIDDEN RESEARCH LANGUAGE:\n"
+ "آليات، أدوات قياس، نظريات، نماذج، استبيان، تشخيص، إجراءات، ممارسات، خصائص، أبعاد، إطار نظري\n\n"
+
+ "FORBIDDEN PHRASES:\n"
+ "في ظل، من خلال، يُعدّ، يبرز، يتجلى، يُسلّط الضوء، تشير الدراسات، أظهرت الأبحاث\n"
+ "If any appear → REWRITE.\n\n"
+
+ "You MUST apply Arabic logical punctuation rules:\n"
+
+ "1) Use SEMICOLON (؛) before:\n"
+ " • Explanation after generalization\n"
+ " • Clarification of a previous idea\n"
+ " • Sentences starting with:\n"
+ " حيث / إذ / لأن / مما + فعل مضارع / بالتالي / وبالتالي\n"
+
+ "2) NEVER join cause–effect or general–specific ideas with a comma only.\n"
+ " If logic exists → punctuation MUST signal it.\n"
+
+ "If logical punctuation is missing → REWRITE THE PARAGRAPH.\n"
+
+
+
+ "=============================\n"
+ "LAYER 2 — OPENING RULE (MANDATORY)\n"
+ "=============================\n"
+
+ "The FIRST sentence MUST hook emotionally or intellectually use the intro style given to choose using ONE of:\n"
+ "• question\n"
+ "• short scene\n"
+ "• realistic moment\n"
+ "• problem\n"
+ "• striking observation\n"
+ ". others\n"
+
+
+ "=============================\n"
+ "LAYER 3 — STYLE RULES\n"
+ "=============================\n"
+
+ "Write like a human author:\n"
+ "• warm\n"
+ "• vivid\n"
+ # "• narrative\n"
+ "• concept-driven\n"
+ "Show ideas instead of defining them.\n"
+ "Avoid textbook tone.\n"
+ "Avoid definitive explanatory closures:\n"
+ "- ليس X بل Y\n"
+ "- هو في جوهره…\n"
+ "- يتمثل في…\n"
+ "Prefer:\n"
+ "• tension\n"
+ "• contrast\n"
+ "• unfolding meaning\n"
+ "• leaving conceptual space open\n\n"
+
+ '=============================\n'
+ 'LAYER 3.5 — ANTI-AI & ANTI-TEMPLATE RULES (CRITICAL)\n'
+ '=============================\n'
+
+ 'You MUST actively break Arabic AI-style patterns.\n'
+
+ '1) DIRECT MENTAL COMMANDS — FORBIDDEN\n'
+ '❌ Never use verbs that push the reader outside the text:\n'
+ 'تخيّل / تأمّل / فكّر / لاحظ / انتبه\n'
+
+ 'Instead:\n'
+ '• Convert the idea into a visible action, scene, or unfolding event.\n'
+ '• Write as if the moment is already happening, not requested.\n\n'
+
+ '2) VAGUE OVERUSED NOUNS — FORBIDDEN UNLESS NECESSARY\n'
+ '❌ Avoid hollow abstractions that produce no image:\n'
+ 'عالم / إطار / أفق / سياق / منظومة / مشهد عام\n'
+
+ 'Rule:\n'
+ '• If removing the word does not change meaning → DELETE it.\n'
+ '• Otherwise replace it with:\n'
+ ' - a concrete action\n'
+ ' - a specific situation\n'
+ ' - a lived position or tension\n\n'
+
+ '3) READY-MADE CONTRAST STRUCTURES — FORBIDDEN\n'
+ '❌ Never use:\n'
+ 'ليس … بل …\n'
+ 'لا يقتصر على … وإنما …\n'
+
+ 'Instead:\n'
+ '• Split the idea into two sentences.\n'
+ '• Let meaning escalate progressively instead of rhetorical opposition.\n\n'
+
+ '4) EXPLANATORY CONNECTORS — RESTRICTED\n'
+ '❌ Avoid turning prose into a report using:\n'
+ 'إذ / مما / حيث / وهذا يعني / مما يؤدي إلى\n'
+
+ 'Allowed only if:\n'
+ '• Logical punctuation (؛ :) is used correctly\n'
+ '• OR the sentence is rewritten as an independent action\n'
+
+ 'Prefer:\n'
+ '• Embedded causality through narrative flow\n'
+ '• Action revealing consequence without explanation\n\n'
+
+ '5) QUESTION + EXPLANATION PATTERN — FORBIDDEN\n'
+ '❌ Never ask a question then neutralize it with:\n'
+ 'هذا السؤال يكشف / يوضح / يعكس\n'
+
+ 'Instead:\n'
+ '• Let the answer unfold through example, tension, or movement.\n'
+ '• The question must open space, not close it.\n\n'
+
+ '6) FILLER TRANSITIONS — FORBIDDEN BY DEFAULT\n'
+ '❌ Avoid empty connectors:\n'
+ 'في هذا السياق / ومن ثم / علاوة على ذلك / في ضوء ذلك\n'
+
+ 'Rule:\n'
+ '• Delete by default.\n'
+ '• Replace only with real:\n'
+ ' - temporal movement\n'
+ ' - causal pressure\n'
+ ' - conceptual shift\n\n'
+
+ '=============================\n'
+ 'LAYER 3.6 — CONTEXT CONTINUITY RULE (CRITICAL)\n'
+ '=============================\n'
+
+ 'You MUST maintain semantic pressure across sentences.\n'
+
+ 'RULE 1 — NO ABSTRACT JUMP\n'
+ '❌ Never jump from:\n'
+ '• concrete challenge → abstract wisdom\n'
+ '• example → slogan\n'
+ '• problem → generalized conclusion\n'
+
+ 'Unless:\n'
+ '• the abstract idea is a DIRECT consequence of the previous sentence\n'
+ '• and the causality is FELT, not declared\n\n'
+
+ 'RULE 2 — TRANSITION VALIDATION\n'
+ 'Before using any transition word (و، لكن، ومع ذلك، وأمام، هكذا):\n'
+
+ 'Ask internally:\n'
+ '"Does the previous sentence FORCE this next sentence?"\n'
+
+ 'If the answer is NO → REWRITE BOTH.\n\n'
+
+ 'RULE 3 — FORBIDDEN SAFE LANDINGS\n'
+ '❌ Avoid sentences that sound like safe endings:\n'
+ '• تكمن القوة في…\n'
+ '• هكذا يصبح…\n'
+ '• من هنا تبدأ…\n'
+ '• الاستكشاف هذا يعد…\n'
+
+ 'These phrases CLOSE meaning instead of advancing it.\n'
+
+ 'Prefer:\n'
+ '• unresolved momentum\n'
+ '• forward pressure\n'
+ '• conceptual instability\n'
+
+
+ "=============================\n"
+ "LAYER 4 — STRUCTURE LOGIC\n"
+ "=============================\n"
+
+ "Paragraph 1 → hook + lived situation\n"
+ "Middle → deepen the concept philosophically/psychologically\n"
+ "Ending → create forward momentum (not summary)\n"
+ "• Every paragraph MUST grow from the previous one.\n"
+ "• Any conceptual shift MUST include:\n"
+ " - a causal connector (فـ / إذ / لذلك / ومن ثم)\n"
+ " - OR a logical punctuation mark (: ؛)\n\n"
+
+ "❌ Forbidden:\n"
+ "- Sudden conclusions without transition\n"
+ "- Isolated sentences that could stand alone\n"
+
+ "If a sentence can be removed without breaking meaning → REWRITE.\n"
+
+
+ "=============================\n"
+ "LAYER 5 — LANGUAGE QUALITY\n"
+ "=============================\n"
+
+ "Arabic must be:\n"
+ "• grammatically perfect\n"
+ "• spelling perfect\n"
+ "• fluid and natural\n"
+ "• no repetition\n\n"
+
+ "=============================\n"
+ "WHY_THIS_CHAPTER_NOW — SCOPE RULE (CRITICAL)\n"
+ "=============================\n"
+
+ 'The field "why_this_chapter_now" serves ONLY as:\n'
+ '• a temporal justification\n'
+ '• a motivational background\n'
+ '• NOT a narrative scope\n\n'
+
+ 'Rules:\n'
+ '1) It MUST NOT dictate geographical focus.\n'
+ '2) Any local reference (country, institution, region) is:\n'
+ ' - CONTEXTUAL\n'
+ ' - NOT foundational\n'
+ '3) Default writing scope is ALWAYS:\n'
+ ' • general\n'
+ ' • conceptual\n'
+ ' • globally applicable\n\n'
+
+ 'Local contexts mentioned in "why_this_chapter_now":\n'
+ '• MAY be abstracted\n'
+ '• MAY be generalized\n'
+ '• MUST NOT dominate the introduction\n\n'
+
+
+ "=============================\n"
+ "SELF-REVISION LOOP (MANDATORY)\n"
+ "=============================\n"
+
+ "After writing:\n"
+ "1) Scan for banned words\n"
+ "2) Remove any list or enumeration\n"
+ "3) Remove academic tone\n"
+ "4) Fix grammar\n"
+ "5) Rewrite any sentence that sounds generic\n\n"
+
+ '6) Scan specifically for:\n'
+ ' - mental verbs\n'
+ ' - vague abstractions\n'
+ ' - rhetorical contrasts\n'
+ ' - filler transitions\n'
+ 'If found → rewrite the entire paragraph, not just the sentence.\n\n'
+
+ "QUESTION HANDLING RULE (CRITICAL)\n"
+ "If a paragraph ends with a question:\n"
+ "1) The following sentence MUST do ONE of:\n"
+ " • Reframe the question conceptually\n"
+ " • Signal that the answer unfolds ahead (implicitly, not structurally)\n"
+ " • Provide a philosophical hinge\n\n"
+
+ "2) NEVER follow a question with:\n"
+ " • a broken nominal sentence\n"
+ " • vague commentary\n"
+ " • unclear subject reference\n"
+
+ "3) Preferred patterns:\n"
+ ' • "الإجابة على هذا السؤال تكمن في..."\n'
+ ' • "هذا السؤال يفتح بابًا نحو..."\n'
+ ' • "من هنا تبدأ الإشكالية الحقيقية..."\n\n'
+
+ 'If the post-question sentence is weak → REWRITE BOTH.\n\n'
+
+
+ "Output ONLY the final introduction text."
+ ),
+ examples=[intro_reference1],
+ llm=model,
+ memory=True,
+ allow_delegation=False,
+ verbose=True
+)
+
+def intro_generation_task(intro_generator_agent):
+ return Task(
+ description=(
+ "You are given structured chapters metadata:\n({chapter_metadata})\n andfocus on intros style for each chapter:\n({intro_style})\n\n"
+ "CRITICAL WRITING RULE — Opening Diversity:\n"
+ "Even if the tone is academic or formal,"
+ "MANDATORY HOOK:\n"
+ "The first sentence MUST be engaging (question, story, scenario, or problem).\n"
+ "Never start with a definition.\n\n"
+ "AI-STYLE BAN:\n"
+ "Never use cliché academic phrases or repeated textbook templates.\n"
+ "If the sentence feels predictable, rewrite it.\n\n"
+ "BANNED VERBS (in all conjugations):\n"
+ "❌ يبرز / تبرز / يُبرز / نبرز / برز / بارز\n"
+ "❌ يتجلى / تتجلى / تجلّى / متجلّي\n"
+ "❌ يُعدّ / تُعدّ / عُدّ\n"
+ "❌ يُسلّط الضوء / نسلّط\n"
+ "❌ يغوص / نغوص\n"
+ "❌ يمتدّ النقاش / يمتدّ\n\n"
+ "BANNED META-DESCRIPTIONS:\n"
+ "❌ هذا الفصل + any verb (يبرز، يقدّم، يستعرض، يتناول، يناقش)\n"
+ "❌ نرى فيه / نُلاحظ هنا / نُتَعَرَّضُ هنا\n"
+ "❌ يدعونا هذا + anything\n"
+ "❌ من هنا، يصبح...\n\n"
+ "BANNED TRANSITIONS:\n"
+ "❌ من خلال (find alternatives: بفضل، عبر، بواسطة، or restructure)\n"
+ "❌ في ظل\n"
+ "❌ عبر استكشاف\n\n"
+ "**WHY THESE ARE BANNED:**\n"
+ "These phrases describe what THE CHAPTER DOES.\n"
+ "The introduction should describe THE CONCEPT, not the chapter's actions.\n\n"
+ "NO DIRECT ADDRESS:\n"
+ "Do not explicitly mention the audience (طلاب، متعلمون، قرّاء).\n"
+ "Use implicit contextual framing instead.\n\n"
+ "ARABIC QUALITY:\n"
+ "Zero spelling, grammar, or phrasing mistakes are allowed.\n"
+ "DO NOT use full tashkeel (vocalization marks) except:\n"
+ "- To disambiguate rare cases\n"
+ "- On the last word of a sentence if needed\n\n"
+ "Academic writing does NOT mean identical openings.\n"
+ "Each chapter MUST begin with a naturally varied opening strategy.\n"
+ "Before writing, internally choose ONE opening style that best fits the chapter according to what style says:\n"
+ "- contextual background\n"
+ "- problem framing\n"
+ "- conceptual importance\n"
+ "- analytical contrast\n"
+ "- research observation\n"
+ "- structural preview\n\n"
+ "=============================\n"
+ "AUDIENCE RULE (REINFORCED)\n"
+ "=============================\n\n"
+ "NEVER use these terms:\n"
+ "❌ المتدرّب / المتدربون\n"
+ "❌ القارئ / القرّاء\n"
+ "❌ الطالب / الطلاب\n"
+ "❌ المتعلّم / المتعلمون\n"
+ "❌ الموظف / الموظفون\n\n"
+ "**This is a BOOK, not a training course.**\n\n"
+ "Rotate openings naturally across chapters.\n"
+ "Never reuse the same opening structure repeatedly.\n"
+ "Avoid formulaic or AI-sounding sentences.\n"
+ "The introduction must feel written by a human author, not generated from a template.\n"
+ "Write ONE introduction that:\n"
+ "1) Follows the style of the chapter intro\n"
+ "2) Reflects the learning outcome\n"
+ "3) Frames all sections conceptually without detailing them\n"
+ "4) Respects scope limits and avoids overlap\n"
+ "5) Matches the declared intro_function\n\n"
+ "CRITICAL — NO SECTION SUMMARY:\n"
+ "Do NOT sequentially describe chapter sections.\n"
+ "Do NOT narrate the structure of the chapter.\n"
+ "The introduction must frame ideas, not summarize contents.\n\n"
+ "=============================\n"
+ "NO UNSOURCED RESEARCH CLAIMS\n"
+ "=============================\n"
+ "NEVER say:\n"
+ "• تشير الدراسات\n"
+ "• أثبتت الأبحاث\n"
+ "• تؤكد الدراسات\n"
+ "• يرى الباحثون\n\n"
+ "Unless a specific study, author, or year is explicitly provided in metadata.\n"
+ "Otherwise, discuss ideas conceptually only.\n\n"
+ "=============================\n"
+ "REQUIRED APPROACH\n"
+ "=============================\n\n"
+ "1. **START**: Hook that engages with the CONCEPT\n"
+ " Example: 'ما الذي يجعل البعض قادرين على...؟'\n\n"
+ "2. **DEVELOP**: Discuss the concept's nature, significance, challenges\n"
+ " - Focus on WHAT THE CONCEPT IS\n"
+ " - Focus on WHY IT MATTERS\n"
+ " - Focus on HOW IT MANIFESTS\n"
+ " - DO NOT focus on what the chapter covers\n\n"
+ "3. **CLOSE**: Connect to reader's context or forward implication\n"
+ " • Set intellectual expectations\n"
+ " • Create forward momentum\n"
+ " • NO phrases like 'هنا نستكشف' or 'هذا الفصل يتناول'\n\n"
+ "=============================\n"
+ "STYLE: AVOID RIGID ACADEMIC TONE\n"
+ "=============================\n\n"
+ "The introduction should be:\n"
+ "• Intellectually engaging (not dry)\n"
+ "• Fluid and connected (not choppy)\n"
+ "• Conceptually rich (not procedurally descriptive)\n"
+ "• Human-sounding (not research-report style)\n\n"
+ "❌ RIGID ACADEMIC STYLE:\n"
+ "'يُعرّف الصمود بأنه قدرة الفرد على التعافي. تشير الدراسات إلى دوره في الأداء.'\n\n"
+ "✅ FLUID ENGAGING STYLE:\n"
+ "'الصمود ليس مجرد قدرة على التحمّل، بل هو فنّ إعادة البناء الداخلي بعد كل اهتزاز.'\n\n"
+ "=============================\n"
+ "TRANSITIONS BETWEEN IDEAS\n"
+ "=============================\n\n"
+ "ALWAYS connect paragraphs smoothly.\n\n"
+ "Use varied transition tools:\n"
+ "• وفي هذا السياق...\n"
+ "• ومن هذا المنطلق...\n"
+ "• وهنا تكمن...\n"
+ "• لكن...\n"
+ "• غير أن...\n"
+ "• بينما...\n"
+ "• ومع ذلك...\n\n"
+ "❌ BAD (choppy jumps):\n"
+ "'الصمود مهم. له أركان. الشخصية الصامدة لها سمات.'\n\n"
+ "✅ GOOD (smooth flow):\n"
+ "'الصمود النفسي يتجاوز القوة الظاهرة. وفي أعماقه، تكمن بنية معقّدة من الأركان النفسية التي تشكّل معًا درعاً داخلياً. وهذا التماسك الداخلي هو ما يميّز...'\n\n"
+ "STYLE REFINEMENT:\n"
+ "Prefer conceptual language over procedural language.\n"
+ "Avoid verbs like: يبدأ، ينتقل، يستعرض، يختتم.\n\n"
+ "FORBIDDEN ROLES:\n"
+ "Never use: متدرّب، مشارك، متعلم في دورة، برنامج تدريبي\n"
+ "This is a BOOK, not training material.\n\n"
+ "FIELD OVERRIDES:\n"
+ "- reader_interaction:\n"
+ " → Prefer conceptual engagement over direct address\n"
+ '- opening_style includes "سؤال":\n'
+ " → Question MAY be implicit, not explicit\n"
+ "- explicit_structure_markers:\n"
+ " → Use conceptual flow, not verbal markers\n"
+ "- voice_type = إرشادي:\n"
+ " → Guide through idea progression, not instructions\n\n"
+ "Length rules:\n"
+ "- conceptual_explanation → 250–350 words\n"
+ "- academic orientation → 450–750 words\n"
+ "- analytical → 350–550 words\n\n"
+ "Output:\n"
+ "- JSON with a single key: intro"
+ ),
+ agent=intro_generator_agent,
+ expected_output="ChapterIntro JSON",
+ output_json=ChapterIntro,
+ # output_file=os.path.join(output_dir, "intro_output.json")
+ )
diff --git a/agents/books/units_structure.py b/agents/books/units_structure.py
new file mode 100644
index 0000000000000000000000000000000000000000..0564dddee67c9d5bd7436f68d6c15e44f62fe0d0
--- /dev/null
+++ b/agents/books/units_structure.py
@@ -0,0 +1,109 @@
+from crewai import Agent, Task
+from modules import llm_4m
+from schemas import CourseSchema
+
+
+def course_structuring_agent():
+ model = llm_4m()
+ return Agent(
+ name="CourseStructuringAgent",
+ role="Educational Content Structuring Expert",
+ goal=(
+ "تحليل تصور فني (أو أكثر) لكتاب/حقيبة تدريبية "
+ "وتحويله إلى هيكل تدريبي JSON واضح ومنضبط بدون كتابة محتوى."
+ ),
+ backstory=(
+ "أنت خبير تصميم مناهج وحقائب تدريبية. "
+ "تجيد التعامل مع ملفات غير منظمة، ومحتوى متكرر أو موزع على أكثر من مستند. "
+ "مهمتك استخراج الهيكل العلمي فقط: وحدات + عناوين فرعية + نواتج تعلم. "
+ "تلتزم التزامًا صارمًا بعدم تغيير أي عنوان ورد كما هو."
+ ),
+ llm=model,
+ verbose=False,
+ memory=False,
+ allow_delegation=False,
+)
+
+
+def course_structuring_task(course_structuring_agent):
+ return Task(
+ agent=course_structuring_agent,
+ output_json=CourseSchema,
+ description="""
+أنت خبير في تصميم المناهج وبناء الحقائب التدريبية الاحترافية.
+
+سيتم تزويدك بـ:
+- نص واحد أو أكثر (قد يكونوا من ملفين مختلفين) يمثلون:
+ • تصور فني للكتاب
+ • وصف الكتاب
+ • نواتج التعلم
+ • الفئة المستهدفة
+ • تقسيم الفصول والعناوين
+
+⚠️ ملاحظات مهمة عن النص:
+- النص قد يحتوي على:
+ - شعارات، أسماء جهات، ترويسات تصميمية
+ - تكرار أو اختلاف في الصياغة
+- هذه العناصر غير التعليمية يجب تجاهلها تمامًا
+- اعتبر كل النصوص كأنها تمثل كتابًا واحدًا
+
+========================
+النصوص المُدخلة:
+========================
+{merged_book_text}
+
+========================
+البيانات الإضافية (قد تكون فارغة):
+========================
+- course_name: {course_name}
+- course_audience: {course_audience}
+- course_description: {course_description}
+- learning_outcomes (إن وُجدت): {learning_outcomes}
+
+========================
+🎯 المطلوب منك:
+========================
+
+1) هيكلة المحتوى:
+- كل فصل = Unit واحد
+- عنوان الفصل = unit_name
+- العناوين أو النقاط داخل الفصل = topics
+- تجاهل المقدمة والخاتمة ككيانات مستقلة
+- ❗ يُمنع منعًا باتًا:
+ - إعادة صياغة العناوين
+ - تحسين لغوي
+ - دمج أو تقسيم العناوين
+
+2) Learning Outcomes:
+- استخدم learning_outcomes المُدخلة كما هي إن وُجدت
+- إذا لم تكن موجودة:
+ - أنشئ Learning Outcomes عامة للكورس
+ - بصياغة تعليمية احترافية (يكون المتدرب قادرًا على...)
+ - لا تكرر عناوين الوحدات حرفيًا
+
+3) course_description:
+- إذا كانت موجودة → لا تغيّرها
+- إذا كانت فارغة → أنشئ وصفًا احترافيًا بناءً على المحتوى
+
+4) course_audience:
+- إذا كانت موجودة → لا تغيّرها
+- إذا كانت فارغة → استنتج الفئة الأنسب بدقة
+
+5) وحدات التدريب:
+- لكل Unit:
+ - unit_name: اسم الفصل كما ورد
+ - topics: قائمة بالعناوين الفرعية فقط
+ - outcome: ناتج تعلم خاص بهذه الوحدة (جملة واحدة)
+
+========================
+📦 الإخراج النهائي:
+========================
+- JSON فقط
+- مطابق تمامًا لـ CourseSchema
+- بدون أي شرح أو نص خارج JSON
+
+⚠️ أي حقل غير موجود في الـ Schema = مرفوض
+""",
+ expected_output="Strict JSON matching CourseSchema schema.",
+ async_execution=False,
+)
diff --git a/agents/content_phase/__init__.py b/agents/content_phase/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..922d89d899c16ffa0a38445e6a31838222a36de8
--- /dev/null
+++ b/agents/content_phase/__init__.py
@@ -0,0 +1,17 @@
+from .final_outlines_before_content import (
+ curriculum_designer,
+ generate_course_structure_task,
+)
+from .old_outlines_transformer import (
+ course_structurer_agent,
+ transform_plan_to_course_task,
+)
+from .keyword_agent import query_agent, query_task
+from .content_generation import course_writer_agent, course_writer_task
+from .quiz_agent import generate_quiz_agent, generate_quiz_task
+from .details_before_content.unit_intro import unit_intro_agent, unit_intro_task
+from .details_before_content.details import units_details_agent, units_details_task
+from .details_before_content.questions_activities_before_content import (
+ units_eval_details_agent,
+ units_eval_details_task,
+)
diff --git a/agents/content_phase/content_generation.py b/agents/content_phase/content_generation.py
new file mode 100644
index 0000000000000000000000000000000000000000..95a3d488b70ed5451dccf24f73762065b6ae9b0e
--- /dev/null
+++ b/agents/content_phase/content_generation.py
@@ -0,0 +1,305 @@
+from crewai import Agent, Task
+import os
+import json
+from modules import llm_open_grok, Example1, Example2, Example3, Example4, Example5
+
+
+def course_writer_agent():
+ model = llm_open_grok()
+
+ return Agent(
+ name="ArabicCourseWriterAgent",
+ role="Arabic Academic Content Synthesizer",
+ goal=(
+ "إنتاج محتوى أكاديمي عربي منظم ومتسلسل منطقيًا، "
+ "ومُعد خصيصًا لمقرر تدريبي يقدّمه المدرب للمتدربين. "
+ "يعتمد المحتوى على scraped content كمصدر معرفة فقط دون نسخ نصي. "
+ "يجب أن يكون كل محور غنيًا بالمعلومات، قابلًا للشرح المباشر، "
+ "ويشرح المفاهيم بعمق وليس بشكل سطحي. "
+ "يجب أن يظهر دور المدرب كقائد تعليمي ومصمم برامج تدريبية، "
+ "مع استخدام أمثلة تطبيقية واقعية وتوثيق علمي وفق APA الإصدار السابع."
+ ),
+ backstory=(
+ "أنت خبير متخصص في تطوير المناهج العربية وإعداد الحقائب التدريبية الأكاديمية، "
+ "وخاصة المقررات المهنية والتطبيقية مثل مقرر: {course_title}. "
+ "تمتلك خبرة واسعة في تصميم البرامج التدريبية وبناء المحتوى التعليمي المنظم "
+ "القابل للتقديم داخل القاعات التدريبية أو عبر المنصات الإلكترونية. "
+ "تتعامل مع المدرب باعتباره قائدًا تعليميًا وليس مجرد ناقل للمعلومات. "
+ "القائد التعليمي هو من يوجه المتدربين نحو أهداف واضحة، "
+ "وينظم عملية التعلم داخل الجلسة التدريبية ويضبط إيقاعها، "
+ "ويحفّز المتدربين على المشاركة الفعالة والتفكير النقدي."
+ "كما تنظر إلى المدرب أيضًا باعتباره مصممًا للبرامج التدريبية، "
+ "حيث يبدأ العمل بتحليل الاحتياجات التدريبية للمتدربين، "
+ "ثم تصميم برنامج تدريبي متكامل يتدرج منطقيًا بين المعرفة والمهارات والتطبيق."
+ "تلتزم دائمًا بالأسلوب الأكاديمي الواضح والدقيق، "
+ "وتشرح كل مفهوم أو عنصر يتم ذكره شرحًا مفصلًا وليس مجرد سرد."
+ "تهتم بالتنظيم البصري للنص بشكل كبير، "
+ "حيث يجب أن تكون كل نقطة في سطر مستقل، "
+ "وأن يتم استخدام العناوين الفرعية والنقاط المرقمة بوضوح."
+ "كما تلتزم بالتوثيق العلمي وفق APA الإصدار السابع، "
+ "مع كتابة أسماء المؤلفين كاملة وذكر نوع المصدر "
+ "(كتاب – PDF – بحث علمي – مصدر أكاديمي)."
+ "المصادر العربية يجب أن تكون هي الأغلب، "
+ "مع السماح بمصدر أجنبي واحد فقط عند الحاجة."
+ ),
+ llm=model,
+ verbose=True,
+ memory=True,
+ examples=[Example1, Example2, Example3, Example4, Example5],
+ allow_delegation=False,
+ )
+
+
+def course_writer_task(course_writer_agent):
+
+ return Task(
+ description=(
+ "أنت تستقبل scraped content كمصدر معرفة فقط (Reference Only — Not Rewriting)، "
+ "ومطلوب منك إنتاج محتوى أكاديمي عربي منظم مرتبط مباشرة بعنوان Subtopic، "
+ "ومناسب ليستخدمه المدرب في الشرح المباشر للمتدربين.\n\n"
+ "=================================================\n"
+ "📌 أولًا: قواعد عامة إلزامية\n"
+ "=================================================\n"
+ "1) ابدأ دائمًا بجملة واضحة تحدد الفكرة الأساسية للمحور.\n"
+ "2) أضف مقدمة قصيرة تربط المحور الحالي بالمحور السابق.\n"
+ "3) امنع أي انحراف عن العنوان؛ يجب أن يخدم كل سطر موضوع المحور مباشرة.\n"
+ "4) لا تكرر الأفكار؛ إذا تكررت الفكرة يجب دمجها في نقطة واحدة واضحة.\n"
+ "5) استخدم لغة علمية واضحة ومباشرة بدون عبارات إنشائية أو شعاراتية.\n"
+ "6) يفضل ألا تتجاوز الجملة 20 كلمة قدر الإمكان.\n"
+ "7) يمنع وضع روابط أو URLs داخل النص.\n"
+ "8) أي مفهوم أو عنصر يتم ذكره يجب شرحه بوضوح ولا يسمح بالاكتفاء بذكره فقط.\n"
+ "9) يجب أن يكون الشرح عميقًا وكافيًا بحيث يستطيع المدرب استخدامه مباشرة في التدريب.\n"
+ "=================================================\n"
+ "📌 ثانيًا: التنظيم البصري للمحتوى (مهم جدًا)\n"
+ "=================================================\n"
+ "1) يجب أن يكون المحتوى منظمًا بصريًا.\n"
+ "2) عند استخدام النقاط يجب أن تكون:\n"
+ " - كل نقطة في سطر مستقل.\n"
+ " - لا تضع عدة نقاط في نفس السطر.\n"
+ "3) استخدم النقاط المرقمة (1،2،3) عند شرح العناصر.\n"
+ "4) استخدم العناوين الفرعية لتنظيم الأفكار داخل المحور.\n"
+ "5) لا تدمج التعريف والأهمية والمبادئ في فقرة واحدة.\n"
+ "6) المحتوى يجب أن يكون منسقًا ومنظمًا بصريًا، "
+ "وليس مجرد سطور متتابعة غير مهيكلة.\n"
+ "7) عند ذكر الأهمية:\n"
+ " - يجب شرحها باستفاضة.\n"
+ " - يمكن أن تكون في صورة نقاط مرقمة (1، 2، 3...).\n"
+ " - تبدأ بجملة تمهيدية توضح لماذا هذا المحور مهم في السياق التدريبي.\n"
+ "8) عند وجود خصائص أو سمات:\n"
+ " - تُعرض بنظام نقاط مرقمة.\n"
+ " - يتم شرح كل خاصية شرحًا واضحًا ومفصلًا.\n"
+ "9) عند وجود أنواع أو تصنيفات:\n"
+ " - يجب شرح كل نوع، وليس مجرد ذكر الأسماء.\n"
+ "10) عند وجود محور تاريخي:\n"
+ " - يتم عرض المحتوى بتسلسل زمني واضح.\n"
+ " - يشمل الفترات القديمة والحديثة.\n"
+ " - يتم شرح كل مرحلة زمنية وسياقها.\n"
+ "11) يمكن استخدام (أولًا، ثانيًا، ثالثًا) "
+ "عند تناول أكثر من فترة زمنية أو أكثر من فرع رئيسي.\n"
+ "12) يجب التركيز على المحور تركيزا صارما وعدم الخوض فى مواضيع اخره داخله لان ذلك سيسبب فى تكرار وايضا "
+ "عند تناول محور عن الادوات او التقنيات يجب التركيز عليها مع شرح كل اداة وطرق استخدامها وعدم الاكتفاء باداة او تقنية واحدة واظهر التنوع\n وعندما يكون محور عن امثلة يجب ذكر امثلة واقعية حقيقية مع ذكر الامثلة مفصلة والتركيز عليها.\n\n"
+ "=================================================\n"
+ "📌 ثالثًا: شرح دور المدرب داخل المحتوى\n"
+ "=================================================\n"
+ "عند الحديث عن التدريب يجب توضيح دور المدرب باعتباره:\n\n"
+ "1) قائدًا تعليميًا:\n"
+ " - يوجه المتدربين نحو أهداف واضحة.\n"
+ " - ينظم عملية التعلم داخل الجلسة التدريبية.\n"
+ " - يدير النقاش ويحفز المشاركة الفعالة.\n"
+ " - يساعد المتدربين على التفكير والتحليل وليس الحفظ فقط.\n\n"
+ "2) مصمم برامج تدريبية:\n"
+ " - يبدأ بتحليل الاحتياجات التدريبية للمتدربين.\n"
+ " - يصمم برنامجًا تدريبيًا متدرجًا.\n"
+ " - يدمج بين المعرفة والمهارات والتطبيق العملي.\n"
+ " - يستخدم أدوات وتقنيات تدريب متنوعة.\n"
+ "=================================================\n"
+ "📌 رابعًا: تنظيم المحتوى داخل المحور\n"
+ "=================================================\n"
+ "يمكن استخدام العناصر التالية حسب طبيعة الموضوع:\n"
+ "- تعريف المفهوم.\n"
+ "- أهمية الموضوع في التدريب.\n"
+ "- الخصائص أو السمات.\n"
+ "- الأنواع أو التصنيفات.\n"
+ "- الأدوات أو التقنيات المستخدمة.\n"
+ "- أمثلة واقعية حقيقية.\n"
+ "- تطبيق عملي أو سيناريو تدريبي.\n"
+ "- خلاصة تربط بالمحور التالي.\n"
+ "=================================================\n"
+ "📌 خامسًا: التوثيق والمصادر\n"
+ "=================================================\n"
+ "1) يتم وضع المراجع في قسم sources فقط.\n"
+ "2) يمنع وضع المراجع داخل generated_content.\n"
+ "3) يجب استخدام APA الإصدار السابع.\n"
+ "4) يجب كتابة أسماء المؤلفين كاملة.\n"
+ "5) يجب ذكر نوع المصدر بجانب المرجع مثل:\n"
+ "(كتاب – PDF – بحث علمي – موقع أكاديمي).\n"
+ "6) يجب أن تكون المصادر مرتبطة مباشرة بموضوع المحور.\n"
+ "7) يجب أن تكون المصادر العربية هي الأغلب.\n"
+ "8) يسمح بمصدر أجنبي واحد فقط عند الحاجة.\n"
+ "=================================================\n"
+ "📌 INPUT DATA\n"
+ "=================================================\n"
+ "Course Title: {course_title}\n"
+ "Unit: {unit_title}\n"
+ "Topic: {topic_title}\n"
+ "Subtopic: {subtopic_title}\n"
+ "Subtopic Description: {subtopic_description}\n"
+ "Scraped content (reference only):\n"
+ "{combined_scraped_texts}\n\n"
+ "=================================================\n"
+ "📌 OUTPUT FORMAT (MANDATORY)\n"
+ "=================================================\n"
+ "Return ONLY a valid JSON object:\n"
+ "{\n"
+ ' "generated_content": "Final Arabic academic content",\n'
+ ' "sources": ["(Author Full Name, Year). Title. Publisher. [Type]"]\n'
+ "}\n\n"
+ "=================================================\n"
+ "📌 FINAL REMINDER\n"
+ "=================================================\n"
+ "- الهدف النهائي هو إنتاج محتوى يستطيع المدرب استخدامه مباشرة في الشرح.\n"
+ "- يجب شرح كل عنصر يتم ذكره.\n"
+ "- التنظيم البصري للنص أولوية قصوى.\n"
+ "- كل نقطة يجب أن تكون في سطر مستقل.\n"
+ "- يجب الالتزام الصارم بموضوع المحور وعدم الخروج عنه.\n"
+ "- المراجع يجب أن تكون منفصلة تمامًا في sources."
+ ),
+ expected_output="JSON with generated_content and sources",
+ agent=course_writer_agent,
+ )
+
+
+# from crewai import Agent, Task
+# import os
+# import json
+# from modules import llm_open_grok,Example1,Example2,Example3,Example4,Example5
+# def course_writer_agent():
+# model=llm_open_grok()
+# return Agent(
+# name="ArabicCourseWriterAgent",
+# role="Arabic Academic Content Synthesizer",
+# goal=(
+# "إنتاج محتوى أكاديمي عربي منظم، متسلسل منطقيًا، "
+# "ومُعد خصيصًا لمقرر تدريبي يقدّمه المدرب للمتدربين. "
+# "يعتمد المحتوى على scraped content كمصدر معرفة فقط دون نسخ نصي. "
+# "يجب أن يكون كل محور قابلًا للشرح المباشر، غنيًا بالمعلومات، "
+# "ومدعومًا بالأمثلة التطبيقية والتوثيق العلمي وفق APA الإصدار السابع. "
+# "كل جزء من المحتوى يجب أن يخدم هدف المقرر ويساعد المدرب على شرحه بسهولة."
+# ),
+# backstory=(
+# "أنت خبير متخصص في تطوير المناهج العربية، "
+# "وإعداد الحقائب التدريبية الأكاديمية للمقررات المهنية والتطبيقية، "
+# "وخاصة مقرر: {course_title}. "
+# "تمتلك خبرة واسعة في بناء محتوى تدريبي متسلسل، "
+# "قابل للعرض والشرح داخل القاعة أو عبر المنصات الإلكترونية. "
+# "تلتزم بالأسلوب الأكاديمي المنضبط، "
+# "والتدرج المنطقي في الأفكار، "
+# "وتشرح كل مفهوم، خاصية، أو عنصر يتم ذكره دون الاكتفاء بسرده فقط. "
+# "تحرص دائمًا على التنظيم البصري للنص، "
+# "واستخدام العناوين الفرعية والنقاط المرقمة، "
+# "مع الالتزام الصارم بالتوثيق العلمي (APA 7) "
+# "من كتب ومراجع علمية عربية وأجنبية ولكن يجب ان يكون العربية الاغلب (PDFs، كتب، أبحاث)."
+# ),
+# llm=model,
+# verbose=True,
+# memory=True,
+# examples=[Example1, Example2, Example3, Example4, Example5],
+# allow_delegation=False,
+# )
+
+# def course_writer_task(course_writer_agent):
+# return Task(
+# description=(
+# "أنت تستقبل scraped content كمصدر معرفة فقط (Reference Only — Not Rewriting)، "
+# "ومطلوب منك إنتاج محتوى أكاديمي عربي منظم، "
+# "مرتبط مباشرة بعنوان الـ Subtopic، "
+# "ومناسب ليستخدمه المدرب في الشرح المباشر للمتدربين.\n\n"
+# "=================================================\n"
+# "📌 أولًا: قواعد عامة إلزامية (لا يُسمح بتجاهلها)\n"
+# "=================================================\n"
+# "1) ابدأ دائمًا بجملة واضحة تُحدد الفكرة الأساسية للمحور.\n"
+# "2) أضف مقدمة تمهيدية قصيرة تربط المحور الحالي بالمحور السابق.\n"
+# "3) امنع أي انحراف عن العنوان؛ أي محتوى جانبي يتم توظيفه فقط لخدمة السياق.\n"
+# "4) لا تكرر الأفكار؛ الفقرات المتشابهة تُدمج في نقطة واحدة متماسكة.\n"
+# "5) استخدم لغة واقعية مباشرة، بدون عبارات شعاراتية أو إنشائية.\n"
+# "6) الجملة الواحدة لا تتجاوز 20 كلمة قدر الإمكان.\n"
+# "7) لا تضع روابط أو URLs داخل النص نهائيًا.\n"
+# "8) أي عنصر يتم ذكره (مفهوم، خاصية، نوع، مبدأ) يجب شرحه، "
+# "ولا يُسمح بالاكتفاء بذكره فقط.\n\n"
+# "=================================================\n"
+# "📌 ثانيًا: تنظيم وبناء المحتوى داخل كل محور\n"
+# "=================================================\n"
+# "1) المحتوى يجب أن يكون منسقًا ومنظمًا بصريًا، "
+# "وليس مجرد سطور متتابعة غير مهيكلة.\n"
+# "2) لا تدمج التعريف، الأهمية، والمبادئ في فقرة واحدة.\n"
+# "3) عند ذكر الأهمية:\n"
+# " - يجب شرحها باستفاضة.\n"
+# " - يمكن أن تكون في صورة نقاط مرقمة (1، 2، 3...).\n"
+# " - تبدأ بجملة تمهيدية توضح لماذا هذا المحور مهم في السياق التدريبي.\n"
+# "4) عند وجود خصائص أو سمات:\n"
+# " - تُعرض بنظام نقاط مرقمة.\n"
+# " - يتم شرح كل خاصية شرحًا واضحًا ومفصلًا.\n"
+# "5) عند وجود أنواع أو تصنيفات:\n"
+# " - يجب شرح كل نوع، وليس مجرد ذكر الأسماء.\n"
+# "6) عند وجود محور تاريخي:\n"
+# " - يتم عرض المحتوى بتسلسل زمني واضح.\n"
+# " - يشمل الفترات القديمة والحديثة.\n"
+# " - يتم شرح كل مرحلة زمنية وسياقها.\n"
+# "7) يمكن استخدام (أولًا، ثانيًا، ثالثًا) "
+# "عند تناول أكثر من فترة زمنية أو أكثر من فرع رئيسي.\n"
+# "8) يجب التركيز على المحور تركيزا صارما وعدم الخوض فى مواضيع اخره داخله لان ذلك سيسبب فى تكرار وايضا "
+# "عند تناول محور عن الادوات او التقنيات يجب التركيز عليها مع شرح كل اداة وطرق استخدامها وعدم الاكتفاء باداة او تقنية واحدة واظهر التنوع\n وعندما يكون محور عن امثلة يجب ذكر امثلة واقعية حقيقية مع ذكر الامثلة مفصلة والتركيز عليها.\n\n"
+# "=================================================\n"
+# "📌 ثالثًا: الأساليب الممكن استخدامها (حسب الحاجة)\n"
+# "=================================================\n"
+# "- تعريف المفهوم أو المهارة.\n"
+# "- أهمية الموضوع في السياق التدريبي.\n"
+# "- المبادئ أو الأسس النظرية المرتبطة بالمحور.\n"
+# "- تطبيق عملي واحد على الأقل (سيناريو أو حالة واقعية قصيرة).\n"
+# "- خلاصة تربط المحور بالمحور أو المهارة التالية.\n"
+# "- يُستخدم هذا الترتيب فقط عندما يخدم طبيعة المحور.\n\n"
+# "=================================================\n"
+# "📌 رابعًا: التوثيق والمصادر\n"
+# "=================================================\n"
+# "1) توثيق جميع الأفكار يكون في نهاية المحور فقط.\n"
+# "2) استخدام نمط APA الإصدار السابع حصريًا.\n"
+# "3) المصادر يجب أن تكون:\n"
+# " - كتب علمية أو مراجع أكاديمية.\n"
+# " - ملفات PDF وأبحاث علمية.\n"
+# " - مصادر عربية وأجنبية (مسموح بالاثنين).\n"
+# " - مسموح بمصدر واحد انجليزيا على الاكثر والاغلب عربية.\n"
+# "4) يُمنع استخدام مواقع عامة كمصدر وحيد دون أصل علمي.\n"
+# "5) يمنع وضع المراجع فى generated_content.\n"
+# "6) يجب أن تذكر المصدر هل هو كتاب او pdf او موقع اكاديمى لازم تكتب جنب كل مصدر نوعه.\n"
+# "6) يجب أن تكون المصادر مرتبطة مباشرة بمحتوى المحور.\n\n"
+# "=================================================\n"
+# "📌 INPUT DATA\n"
+# "=================================================\n"
+# "Course Title: {course_title}\n"
+# "Unit: {unit_title}\n"
+# "Topic: {topic_title}\n"
+# "Subtopic: {subtopic_title}\n"
+# "Subtopic Description: {subtopic_description}\n"
+# "Scraped content (reference only):\n"
+# "{combined_scraped_texts}\n\n"
+# "=================================================\n"
+# "📌 OUTPUT FORMAT (MANDATORY)\n"
+# "=================================================\n"
+# "Return ONLY a valid JSON object (parsable by json.loads):\n"
+# "{\n"
+# ' "generated_content": "Final well-structured Arabic academic content",\n'
+# ' "sources": ["(Author, Year). Title. Publisher.", "(Author, Year). Title. Source."]\n'
+# "}\n\n"
+# "=================================================\n"
+# "📌 FINAL REMINDER\n"
+# "=================================================\n"
+# "- الهدف النهائي: محتوى يستطيع المدرب استخدامه مباشرة في الشرح.\n"
+# "- أي عنصر مذكور يجب شرحه بوضوح.\n"
+# "- التنظيم والتنسيق أولوية قصوى.\n"
+# "- يجب التركيز على المحور وعدم الخروج عن موضوعه وتنظيم الكلام عنه وشرحه باستفاضة.\n"
+# "- عدم وضع المصادر والمراجع مع الكونتنت يجب ان يكونوا منفصلين فى sources."
+# # "اعتمد في تسلسل المحتوى على ما تم شرحه في المحور السابق: {previous_context} لتجنب التكرار وتحقيق الترابط المنطقي."
+# ),
+# expected_output="JSON with generated_content and sources",
+# agent=course_writer_agent,
+# )
diff --git a/agents/content_phase/details_before_content/details.py b/agents/content_phase/details_before_content/details.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b5789d0a2551047c0a75bd3791fc6e5046f6200
--- /dev/null
+++ b/agents/content_phase/details_before_content/details.py
@@ -0,0 +1,58 @@
+from crewai import Agent, Task
+import os
+import json
+from modules import llm_4m
+from schemas import Units_details_output
+
+
+def units_details_agent():
+ model = llm_4m()
+ return Agent(
+ role="مصمم مناهج تعليمية",
+ goal=(
+ "Transform the detailed course structure produced by the curriculum_designer into a higher-level pedagogical expansion for each unit.\n\n"
+ "inputs:\n"
+ "- course_name: {course_name}\n"
+ "- course_audience: {course_audience}\n"
+ "- units: {units}\n"
+ "مرجع: استخدم المثال التالي كنموذج لإنتاج محتوى مفصل:"
+ "{example_reference}\n\n "
+ "Your output MUST follow the Units_details_output and UnitExpansion Pydantic models exactly.\n"
+ "For EACH unit, generate:\n"
+ "1. صياغة نواتج تعلم محددة، واضحة، قابلة للقياس، ومرتبطة بأهداف المقرر.\n"
+ "2. توضيح المعارف والمهارات المتضمنة في بداية كل وحدة.\n"
+ "3. تقديم مقدمة وجيزة تصف الهدف العام للوحدة.\n\n"
+ "ركز على جعل المحتوى مناسبًا للفئة المستهدفة المحددة في course_audience, مع الالتزام بنمط المثال المرجعي."
+ ),
+ backstory=(
+ "أنت مطوّر وحدات تدريبية ذو خبرة واسعة في إعداد المحتوى التعليمي الاحترافي. "
+ "تتعلم من المثال المرجعي المقدم لك لضمان إنتاج محتوى متسق، عملي، "
+ "ومتوافق مع المعايير التعليمية الحديثة. "
+ "دورك هو الارتقاء بمخرجات المصمم السابق إلى مستوى أعلى من التنظيم البيداغوجي، "
+ "مع الحفاظ على وضوح الأهداف، قابلية القياس، والتدرج المنطقي في نواتج التعلم."
+ ),
+ verbose=True,
+ memory=True,
+ llm=model,
+ allow_delegation=False,
+ )
+
+
+def units_details_task(units_details_agent):
+ return Task(
+ description=(
+ "make a new JSON matching Units_details_output. For each unit:\n"
+ "- Use the unit topics/subtopics to infer its scope.\n"
+ "- Generate measurable unit_objectives.\n"
+ "- Write a clear, short unit_description showing knowledge, and skills.\n"
+ "- Produce measurable learning_outcomes linked to the objectives.\n\n"
+ "The output MUST strictly follow: Units_details_output → expanded_units → UnitExpansion."
+ ),
+ expected_output=(
+ "Units_details_output JSON: fields: course_name, course_audience, expanded_units"
+ ),
+ output_json=Units_details_output,
+ agent=units_details_agent,
+ async_execution=False,
+ # output_file=os.path.join(output_dir, 'unit_expantion.json'),
+ )
diff --git a/agents/content_phase/details_before_content/questions_activities_before_content.py b/agents/content_phase/details_before_content/questions_activities_before_content.py
new file mode 100644
index 0000000000000000000000000000000000000000..683e3eaa7e5cc99f98d222ac567169f4426d3635
--- /dev/null
+++ b/agents/content_phase/details_before_content/questions_activities_before_content.py
@@ -0,0 +1,62 @@
+from crewai import Agent, Task
+import os
+import json
+from schemas import Units_eval_details
+from modules import llm_4m
+
+def units_eval_details_agent():
+ model = llm_4m()
+ return Agent(
+ role="مصمم مناهج تعليمية احترافي",
+ goal=(
+ "Transform the structured units coming from curriculum_designer into a fully pedagogical expansion for EACH unit.\n\n"
+ "You MUST generate for every unit the following fields exactly as defined in the EvalDetails model:\n"
+ "- trainer_instructions\n"
+ "- eval_questions\n"
+ "- If this is the FIRST UNIT ONLY, also generate:\n"
+ " • opening_activity\n"
+ " • question_after_opening_activity\n\n"
+ "You MUST learn from the provided example reference:\n"
+ "{example_reference}\n\n"
+ "and then produce NEW, CREATIVE, pedagogy-aligned content consistent with the course context.\n\n"
+ "Inputs:\n"
+ "- course_name: {course_name}\n"
+ "- course_audience: {course_audience}\n"
+ "- units: {units}\n\n"
+ "The output MUST strictly follow the Units_eval_details and EvalDetails Pydantic models.\n"
+ "Ensure that ALL generated content matches the style, structure, tone, and depth shown in the example reference.\n"
+ "Focus on making the content appropriate and engaging for the course_audience and logically aligned with the topics/subtopics of each unit."
+ ),
+ backstory=(
+ "أنت مطوّر وحدات تدريبية ذو خبرة واسعة في إعداد المحتوى التعليمي الاحترافي. "
+ "تتعلم من المثال المرجعي المقدم لك لضمان إنتاج محتوى متسق، عملي، "
+ "ومتوافق مع المعايير التعليمية الحديثة. "
+ "دورك هو الارتقاء بمخرجات المصمم السابق إلى مستوى أعلى من التنظيم البيداغوجي، "
+ "مع الحفاظ على اضافة لمستك الإبداعية دون الخروج عن النمط التعليمي الاحترافي."
+ ),
+ verbose=True,
+ memory=True,
+ llm=model,
+ allow_delegation=False,
+)
+
+def units_eval_details_task(units_eval_details_agent):
+ return Task(
+ description=(
+ "Generate a new JSON strictly matching the Units_eval_details model.\n\n"
+ "For EACH unit in the provided list:\n"
+ "- Analyze the unit_name, outcome, and topics/subtopics to understand scope and depth.\n"
+ "- Produce trainer_instructions and eval_questions.\n"
+ "- For the FIRST unit ONLY, also generate opening_activity and question_after_opening_activity.\n\n"
+ "The output MUST strictly follow the hierarchical structure:\n"
+ "Units_eval_details → EvalDetails.\n"
+ "Content must follow the style demonstrated in example_reference and remain consistent with the course audience."
+ ),
+ expected_output=(
+ "Units_eval_details JSON: fields: course_name, course_audience, expanded_units"
+ ),
+ output_json=Units_eval_details,
+ agent=units_eval_details_agent,
+ async_execution=False,
+ # output_file=os.path.join(output_dir, 'Units_eval_details.json'),
+)
diff --git a/agents/content_phase/details_before_content/unit_intro.py b/agents/content_phase/details_before_content/unit_intro.py
new file mode 100644
index 0000000000000000000000000000000000000000..0713849656aa770145e9720a328fcbf63d28fea7
--- /dev/null
+++ b/agents/content_phase/details_before_content/unit_intro.py
@@ -0,0 +1,131 @@
+from crewai import Agent, Task
+import os
+import json
+from schemas import Units_Introduction
+from modules import llm_g
+def unit_intro_agent():
+ model = llm_g()
+ return Agent(
+ role="كاتب مقدمات تعليمية متخصص",
+ goal=(
+ "كتابة مقدمة (وصف موضوع) شاملة واحترافية لكل وحدة دراسية بناءً على تفاصيلها.\n\n"
+ "المدخلات المطلوبة:\n"
+ "- course_name: {course_name} - اسم المقرر\n"
+ "- course_audience: {course_audience} - الفئة المستهدفة\n"
+ "- units: {units} - قائمة الوحدات \n\n"
+ "المثال المرجعي:\n"
+ "{example_reference}\n\n"
+ "متطلبات كتابة المقدمة (unit_introduction):\n"
+ "1. ابدأ بجملة افتتاحية قوية توضح أهمية الموضوع ومكانته في المقرر\n"
+ "2. اشرح السياق العام والهدف الرئيسي من الوحدة\n"
+ "3. وضّح العلاقة بين الموضوع والممارسة المهنية أو التطبيق العملي\n"
+ "4. اذكر الجوانب النظرية والعملية المتضمنة\n"
+ "5. قسّم المحتوى إلى محاور رئيسية واضحة (2-4 محاور)\n"
+ "6. أظهر القيمة المضافة والفوائد للمتعلم\n"
+ "7. استخدم لغة واضحة، مهنية، ومحفزة\n"
+ "8. الطول المناسب: 500-700 كلمة\n\n"
+ "معايير الجودة:\n"
+ "- التوافق مع مستوى الفئة المستهدفة ({course_audience})\n"
+ "- الاتساق التام مع أسلوب ونمط المثال المرجعي\n"
+ "- الترابط المنطقي والتدفق السلس للأفكار\n"
+ "- تغطية شاملة دون إسهاب ممل أو اختصار مخل"
+ ),
+ backstory=(
+ "أنت كاتب محتوى تعليمي متخصص بخبرة 12 عامًا في كتابة المقدمات والأوصاف للمقررات الدراسية. "
+ "تتميز بقدرتك الفائقة على:\n"
+ "- تحليل محتوى الوحدة (المواضيع، الأهداف، النواتج) واستخلاص الجوهر\n"
+ "- صياغة مقدمات جذابة تثير اهتمام المتعلم وتوضح قيمة المحتوى\n"
+ "- كتابة نصوص متوازنة بين العمق الأكاديمي والوضوح والبساطة\n"
+ "- التعلم من الأمثلة المرجعية والحفاظ على الاتساق الأسلوبي\n"
+ "- مراعاة خصائص الفئة المستهدفة في اختيار المفردات وأسلوب الطرح\n\n"
+ "مهمتك الأساسية:\n"
+ "تحويل المعلومات الأولية عن الوحدة (الأهداف والمواضيع والنواتج) إلى مقدمة تعليمية احترافية "
+ "تحقق الأهداف التالية:\n"
+ "✓ جذب انتباه المتعلم وتحفيزه\n"
+ "✓ توضيح السياق والأهمية\n"
+ "✓ تقديم خارطة واضحة للمحتوى\n"
+ "✓ إظهار الصلة بالواقع العملي\n"
+ "✓ بناء توقعات واقعية عن الوحدة\n\n"
+ "أنت ملتزم بمعايير الجودة العالية والاتساق مع النماذج المرجعية المقدمة."
+ ),
+ verbose=True,
+ memory=False,
+ llm=model,
+ allow_delegation=False,
+ output_pydantic=Units_Introduction,
+)
+
+# إنشاء Task
+def unit_intro_task(unit_intro_agent):
+ return Task(
+ description=(
+ "مهمتك هي إنتاج ملف JSON يحتوي على مقدمة (unit introduction) احترافية لكل وحدة.\n\n"
+ "خطوات العمل لكل وحدة:\n\n"
+ "1. التحليل والفهم:\n"
+ " - اقرأ بعناية: unit_name, topics, unit_objectives, learning_outcomes\n"
+ " - حدد الموضوع الرئيسي والأفكار المحورية\n"
+ " - افهم المستوى المعرفي والمهاري المطلوب\n"
+ " - حدد العلاقة بين الوحدة والمقرر العام\n\n"
+ "2. الاستلهام من المثال المرجعي:\n"
+ " - ادرس بنية المقدمات في المثال المرجعي\n"
+ " - لاحظ: الافتتاحية، تنظيم الفقرات، أسلوب السرد، طول النص\n"
+ " - حافظ على نفس المستوى من العمق والوضوح\n\n"
+ "3. كتابة المقدمة (unit_description):\n"
+ " أ) الفقرة الافتتاحية (2-3 جمل):\n"
+ # new
+ " - لا تبدأ أكثر من مقدمتين بنفس الفعل'\n"
+ " - كل وحدة يجب أن تبدأ بأسلوب افتتاح مختلف من حيث:\n"
+ " • زاوية الطرح\n"
+ " • البنية اللغوية\n"
+ " • نقطة الدخول للفكرة\n"
+ #
+ " - وضّح أهمية الموضوع ومكانته في المجال\n"
+ " - اذكر الهدف الرئيسي من الوحدة\n"
+ " - Avoid overused phrases (e.g., هل تساءلت يومًا، في عالمنا المتسارع…)\n"
+ " - Avoid flashy, promotional, or vague language\n"
+ " - Mix short and long sentences to vary rhythm\n"
+ " - Include a personal touch: surprise, observation, or simple opinion\n"
+ " - Use natural transitions from the idea itself\n"
+ # new
+ "أنماط افتتاح إلزامية (اختر نمطًا مختلفًا لكل وحدة):\n"
+ " 1) افتتاح سياقي: - يبدأ بوصف سياق أو مشكلة حقيقية مرتبطة بالمجال\n"
+ " 2) افتتاح مفاهيمي: - يبدأ بتفكيك مفهوم أساسي أو فكرة محورية\n"
+ " 3) افتتاح تطبيقي:- يبدأ من موقف مهني أو ممارسة عملية\n"
+ " 4) افتتاح تفسيري: - يبدأ بشرح سبب أهمية الموضوع أو أثره"
+ " 5) افتتاح تحليلي: - يبدأ بمقارنة، تصنيف، أو تساؤل تحليلي غير مباشر\n"
+ #
+ " ب) فقرة السياق والتطبيق (2-4 جمل):\n"
+ " - اشرح العلاقة بين النظرية والتطبيق\n"
+ " - وضّح كيف يستفيد المتعلم من هذه الوحدة عمليًا\n"
+ " - أظهر الارتباط بالواقع المهني أو الحياتي\n"
+ " ج) فقرة المحاور (اختيارية):\n"
+ " - إذا كانت الوحدة تحتوي على محاور واضحة، اذكرها بالترقيم:\n"
+ " 'يُركّز المحتوى على ... محاور رئيسية:'\n"
+ " '1- ...: ...'\n"
+ " '2- ...: ...'\n"
+ " د) فقرة الجانب العملي (اختيارية - حسب طبيعة الوحدة):\n"
+ " - إذا كانت الوحدة تتضمن تدريبات أو تطبيقات، اذكرها:\n"
+ " 'وفي الجانب التطبيقي، يتدرب المتدربون على...'\n\n"
+ "4. المراجعة والتدقيق:\n"
+ " - تأكد من الاتساق مع أسلوب المثال المرجعي\n"
+ " - راجع السلاسة اللغوية والترابط المنطقي\n"
+ " - تحقق من الطول (500-700 كلمة)\n"
+ " - تأكد من مناسبة المحتوى للفئة المستهدفة\n\n"
+ "ملاحظات هامة:\n"
+ "- استخدم الضمير 'المتدرب' أو 'المتعلم' حسب السياق\n"
+ "- استخدم أفعالًا قوية: يُعدّ، تُعدّ، يهدف، يُركّز، تتناول، يُسهم، يُمكّن\n"
+ "- تجنب التكرار والحشو\n"
+ "- حافظ على الطابع المهني والأكاديمي دون جفاف\n"
+ "- اجعل المقدمة محفزة وجاذبة للقراءة\n"
+ "-لا تكرر الافعال في بداية المقدمات قم بالتنويع\n\n"
+ "الناتج النهائي:\n"
+ "يجب أن يكون JSON متوافق مع: Units_introductions → UnitIntro → Units_introductions"
+ ),
+ expected_output=(
+ "Units_Introduction JSON: fields: course_name, course_audience, expanded_units"
+ ),
+ output_json=Units_Introduction,
+ agent=unit_intro_agent,
+ async_execution=False,
+ # output_file=os.path.join(output_dir, 'units_introductions.json'),
+)
diff --git a/agents/content_phase/final_outlines_before_content.py b/agents/content_phase/final_outlines_before_content.py
new file mode 100644
index 0000000000000000000000000000000000000000..65b6e4486ccc3fa0dfc33dbe05fbaf739a3c1193
--- /dev/null
+++ b/agents/content_phase/final_outlines_before_content.py
@@ -0,0 +1,72 @@
+from crewai import Agent, Task
+import os
+import json
+from modules import llm_4m
+from schemas import CourseContent
+
+# -------------------------
+# 1. تعريف Agent: Curriculum Designer
+# -------------------------
+def curriculum_designer():
+ model = llm_4m()
+ return Agent(
+ role="مصمم مناهج تعليمية",
+ goal=(
+ # "أنت مصمم مناهج تعليمية. مهمتك هي تحويل بيانات المقرر إلى خريطة تعلمية مفصلة."
+ "أنت مصمم مناهج ذو خبرة عالية. مهمتك تحويل بيانات المقرر إلى خريطة تعلمية مفصلة تشمل وحدات، موضوعات، ونقاط فرعية (subtopics)"
+ "يمكن شرحها مباشرة من قبل مدرب للمتدربين. رتب المحتوى من المفاهيم الأساسية إلى التطبيق العملي، مع مراعاة وضوح كل نقطة وغرضها التعليمي للفئة المستهدفة."
+ "المُدخلات:"
+ "- course_name: {course_name}"
+ "- course_audience: {course_audience}"
+ "- course_description: {course_description}"
+ "- learning_outcomes: {learning_outcomes}"
+ "- units: {units}"
+ "مرجع: استخدم المثال التالي كنموذج لإنتاج محتوى مفصل:"
+ "{example_reference}"
+ "لكل وحدة في units:"
+ " - لكل موضوع أصلي، أنشئ 2-5 نقاط فرعية (subtopics) مفصلة."
+ " - لكل subtopic:"
+ " - title: عبارة قصيرة."
+ " - description: 1-2 جمل تشرح الفكرة والغرض التعليمي."
+ " - رتب النقاط من الأساسيات للتطبيق العملي."
+ " - ركز على جعل المحتوى مناسبًا للفئة المستهدفة المحددة في course_audience."
+ "تحويل بيانات المقرر إلى بنية مفصلة تشمل وحدات وموضوعات ونقاط فرعية، "
+ "مناسبة لأي فئة مستهدفة، مع الالتزام بنمط المثال المرجعي."
+ ),
+ backstory=(
+ "أنت مصمم مناهج ذو خبرة عالية. مهمتك هي ان تتعلم من المثال المرجعي لإنشاء محتوى عملي و تحليل بيانات المقرر وإنتاج خريطة تعلمية تفصيلية تشمل وحدات،"
+ "موضوعات، ونقاط فرعية (subtopics) يمكن شرحها مباشرة من قِبل مدرب لمتدربين،"
+ "مع ترتيبها من الأساسيات إلى التطبيق العملي، مع مراعاة {course_audience}الفئة المستهدفة."
+ # "أنت مصمم مناهج ذو خبرة عالية، تتعلم من المثال المرجعي لإنشاء محتوى عملي، "
+ # "متدرج، وعملي لأي audience."
+ ),
+ verbose=True,
+ memory=True,
+ llm=model,
+ allow_delegation=False,
+)
+
+# -------------------------
+# 2. Task: إنشاء نواتج JSON مفصلة
+# -------------------------
+def generate_course_structure_task(curriculum_designer):
+ return Task(
+ description=(
+ "تحويل بيانات المقرر (course_name, course_audience, units) إلى JSON مفصل يشمل expanded_units. "
+ "لكل موضوع، أنشئ 2-5 subtopics، كل subtopic يحتوي على title و description قصيرة تشرح الفكرة والغرض التعليمي. "
+ # "مع مراعاة أن تكون قابلة للشرح من قبل مدرب للمتدربين. رتب النقاط من المفاهيم الأساسية إلى التطبيق العملي."
+ "تأكد أن كل subtopic يمكن شرحه مباشرة من قبل مدرب للمتدربين. "
+ "رتب النقاط من المفاهيم الأساسية إلى التطبيق العملي، وأضف أمثلة عملية إذا أمكن."
+ ),
+ # description=(
+ # "تحويل بيانات المقرر (course_name, course_audience, units) إلى JSON مفصل "
+ # "يشمل expanded_units. لكل موضوع، أنشئ 2-5 subtopics، كل subtopic يحتوي على title و description."
+ # ),
+ expected_output=(
+ "CourseContent JSON: fields: course_name, course_audience, expanded_units"
+ ),
+ agent=curriculum_designer,
+ output_json=CourseContent,
+ async_execution=False,
+ # output_file=os.path.join(output_dir, "تحليل البيانات.json"),
+)
diff --git a/agents/content_phase/keyword_agent.py b/agents/content_phase/keyword_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..b695d5bbd23a369ca3cf2ebeb12d599bbe1b3247
--- /dev/null
+++ b/agents/content_phase/keyword_agent.py
@@ -0,0 +1,35 @@
+from crewai import Agent, Task, Crew
+from modules import llm_open_nova
+from schemas import CourseWithQueries # فيه الـ Pydantic model بتاعك
+
+# ==== Define Agent ====
+def query_agent():
+ model = llm_open_nova()
+ return Agent(
+ name="SearchQueryAgent",
+ role="Generate 3 short, relevant search queries for each subtopic in the course",
+ goal=(
+ "For each subtopic in the course JSON, generate 3 short, precise, SEO-friendly search queries "
+ "related to topic. Avoid vague, repetitive, or off-topic queries."
+ ),
+ backstory=(
+ "This agent is a research strategist for the course. It creates queries suitable for "
+ "web search to gather useful, relevant content for each subtopic."
+ ),
+ verbose=True,
+ llm=model,
+)
+
+# ==== Task Definition ====
+def query_task(query_agent):
+ return Task(
+ name="Generate 3 search queries in arabic and english per subtopic",
+ description=(
+ "Read the course JSON structure and generate 3 diverse queries per subtopic arabic and english "
+ "Course json is: {course} Queries must be concise, specific, and relevant."
+ ),
+ expected_output="A valid JSON following CourseWithQueries schema",
+ output_json=CourseWithQueries,
+ # output_file=output_file,
+ agent=query_agent,
+)
diff --git a/agents/content_phase/old_outlines_transformer.py b/agents/content_phase/old_outlines_transformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca9887384d7d4b7b979ff721bbe481068310584c
--- /dev/null
+++ b/agents/content_phase/old_outlines_transformer.py
@@ -0,0 +1,88 @@
+from crewai import Agent, Task, Crew
+from modules import llm_4m
+from schemas import CourseData # فيه الـ Pydantic model بتاعك
+
+
+def course_structurer_agent():
+ model = llm_4m()
+ return Agent(
+ role="Instructional Designer",
+ goal=(
+ "تحويل مخطط برنامج تدريبي (بصيغة JSON) إلى هيكل موحّد لمقرر "
+ "تدريبي باسم course_data."
+ ),
+ backstory=(
+ "خبير تصميم تعليمي يقوم ببناء توصيفات مقررات تدريبية، "
+ "ويحوّل المحاور والأهداف العامة إلى مخرجات تعلم ووحدات وموضوعات."
+ ),
+ llm=model,
+ verbose=True,
+)
+
+def transform_plan_to_course_task(course_structurer_agent):
+ return Task(
+ description=(
+ "أنت خبير تصميم تعليمي.\n"
+ "سيتم تزويدك بالمدخلات التالية:\n"
+ "1) plan_json: وهو JSON يمثل مخطط برنامج تدريبي كما يلي:\n"
+ "{plan_json}\n\n"
+ "2) audience_text: نص أولي يصف الفئة المستهدفة:\n"
+ "{audience_text}\n\n"
+ "مهمتك هي إنتاج كائن JSON جديد باسم course_data "
+ "له البنية التالية بالضبط:\n\n"
+ "course_data = {\n"
+ ' "course_name": "اسم المقرر",\n'
+ ' "course_audience": "وصف موسَّع للفئة المستهدفة",\n'
+ ' "course_description": "وصف عام للمقرر",\n'
+ ' "learning_outcomes": [\n'
+ " // عبارات مخرجات تعلم\n"
+ " ],\n"
+ ' "units": [\n'
+ " {\n"
+ ' "outcome": "مخرج تعلم للوحدة",\n'
+ ' "unit_name": "اسم الوحدة",\n'
+ ' "topics": [\n'
+ ' "موضوع 1",\n'
+ ' "موضوع 2",\n'
+ ' "..."\n'
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n\n"
+ "قواعد البناء:\n"
+ "1) استخرج اسم المقرر من حقل main_concept داخل plan_json "
+ 'واستخدمه كـ "course_name" بعد تحسين صياغته إن لزم.\n\n'
+ '2) استخدم audience_text كأساس لبناء "course_audience" ولكن:\n'
+ " - أَعِد صياغته صياغة لغوية قوية وواضحة.\n"
+ " - وسِّع الوصف بإضافة تفاصيل مناسبة عن الفئة المستهدفة "
+ " (مثل نوع خبرتهم، احتياجاتهم التدريبية، بيئتهم التعليمية)،\n"
+ " - مع الحفاظ على المعنى الأصلي وعدم اختلاق فئة مختلفة.\n\n"
+ '3) ابنِ "course_description" استناداً إلى:\n'
+ " - main_concept من plan_json\n"
+ " - General_objectives_of_the_plan من plan_json\n"
+ " - وصف المحاور (focus) في validated_units داخل plan_json\n"
+ " بحيث يكون الوصف فقرة أو فقرتين متماسكتين تشرح هدف المقرر ومحتواه.\n\n"
+ '4) صِغ "learning_outcomes" كقائمة من مخرجات تعلم (حوالي 8 إلى 15 مخرجاً) '
+ "مستندة إلى:\n"
+ " - الأهداف العامة General_objectives_of_the_plan\n"
+ " - المحاور الرئيسية validated_units ومحاورها الفرعية axes (title, purpose).\n"
+ " على أن تبدأ كل عبارة بفعل مضارع واضح مثل: توضح، تحدد، تطبق، تميز، تحلل...\n\n"
+ '5) تكوين الوحدات "units" كالتالي (انتبِه جيداً):\n'
+ ' - لكل عنصر من validated_units في plan_json يجب إنشاء وحدة واحدة فقط في قائمة "units".\n'
+ " - لا تحوِّل العناصر داخل axes إلى وحدات منفصلة.\n"
+ " - unit_name = قيمة الحقل title لكل عنصر داخل validated_units (عنوان المحور الرئيسي).\n"
+ " - outcome = إعادة صياغة الحقل focus لنفس العنصر في صورة جملة مخرج تعلم مختصرة "
+ " تعبّر عن الهدف العام لهذه الوحدة.\n"
+ " - topics = قائمة الموضوعات الفرعية المأخوذة كما هي من الحقول title داخل axes "
+ " التابعة لنفس الوحدة، وبنفس الترتيب.\n"
+ " أي أن topics = [axis_1.title, axis_2.title, ...] دون إضافة موضوعات جديدة "
+ " ودون حذف أي موضوعات، ودون تغيير معاني العناوين.\n\n"
+ "6) يجب أن يكون المخرج النهائي JSON صالح نحويًا، بدون أي شرح إضافي،\n"
+ " أي: أطبع كائن course_data فقط ولا تضف نصوصاً خارجه.\n\n"
+ "7) استخدم اللغة العربية الفصحى في جميع النصوص، "
+ "مع الحفاظ على أسلوب مهني يناسب الأدلة التدريبية."
+ ),
+ agent=course_structurer_agent,
+ expected_output="JSON واحد بصيغة course_data فقط.",
+ output_json=CourseData,
+)
diff --git a/agents/content_phase/quiz_agent.py b/agents/content_phase/quiz_agent.py
new file mode 100644
index 0000000000000000000000000000000000000000..47f1cebbca468dcae5fb9f85e0422cff12170b46
--- /dev/null
+++ b/agents/content_phase/quiz_agent.py
@@ -0,0 +1,67 @@
+from crewai import Agent, Task, Crew
+from modules import llm_g
+from schemas import QuizOutput # فيه الـ Pydantic model بتاعك
+
+def generate_quiz_agent():
+ model = llm_g()
+ return Agent(
+ role="مصمم أسئلة تدريبية",
+ goal=(
+ "إنشاء 20 سؤالًا تدريبيًا عالي الجودة مبنية على المحتوى التعليمي المقدم. "
+ "يجب أن تشمل الأسئلة مزيجًا من أسئلة مباشرة تتحقق من قراءة المتدرب للمحتوى، "
+ "وأسئلة تحليلية تتطلب فهمًا عميقًا واستنتاجًا. "
+ "المطلوب إنتاج أسئلة اختيار من متعدد وصح/خطأ باللغة العربية."
+ ),
+ backstory=(
+ "أنت خبير تربوي متخصص في القياس والتقويم، تعمل منذ 15 عاماً في تصميم الاختبارات الأكاديمية. "
+ "تتميز بقدرتك على صياغة أسئلة دقيقة تكشف مستوى استيعاب المتعلم، "
+ "وتدمج بين الأسئلة المباشرة وأسئلة الفهم العميق."
+ ),
+ verbose=True,
+ memory=False,
+ llm=model,
+ allow_delegation=False,
+)
+
+def generate_quiz_task(generate_quiz_agent):
+ return Task(
+ description=(
+ "أنشئ 20 سؤالًا تدريبيًا بناءً على المعلومات التالية:\n"
+ "- course_name: {course_name}\n"
+ "- course_audience: {course_audience}\n"
+ "- unit_name: {unit_name}\n"
+ "- unit_outcome: {unit_outcome}\n"
+ "- topics: {topics}\n"
+
+ "هيكل الأسئلة المطلوب:\n"
+ " - 5 أسئلة مباشرة للتحقق من قراءة المتدرب للمحتوى (مسموح باستخدام معلومات ظاهرية من النص).\n"
+ " - 10 أسئلة اختيار من متعدد متدرجة من المتوسطة إلى الصعبة تعتمد على التحليل والفهم.\n"
+ " - 5 أسئلة صح/خطأ تعتمد على الاستنتاج وربط المفاهيم.\n\n"
+
+ "## معايير الجودة الإلزامية:\n"
+ "✅ لا تستخدم أبداً صيغ مثل: 'وفقاً للنص'، 'ذُكر في المحتوى'، 'كما ورد او اي كلمات تدل على المحتوى في الاسئله'\n"
+ "✅ استخدم أمثلة وسياقات لم تُذكر مباشرة في المحتوى\n"
+ "✅ تجنب الخيارات الواضحة الخطأ مثل 'كل ما سبق' أو 'لا شيء مما سبق'\n"
+ "✅ اجعل المُشتتات (الخيارات الخاطئة) مبنية على أخطاء مفاهيمية شائعة\n"
+ "✅ وايضاح ال topic الذي اعمد عليه السؤال كل سؤال يجب أن يكون مصحوباً بشرح تفصيلي للإجابة الصحيحة\n"
+ "✅ تأكد من أن الإجابة على كل سؤال موجودة فعلاً في المحتوى المقدم\n\n"
+
+ "قواعد عامة:\n"
+ "✔️ الأسئلة المباشرة يجب أن تعتمد على معلومة واضحة موجودة داخل المحتوى.\n"
+ "✔️ الأسئلة التحليلية يجب أن تعتمد على الفهم العميق وليس النسخ المباشر.\n"
+ "✔️ تجنّب الأسئلة البديهية أو التي لا تحتاج قراءة المحتوى.\n"
+ "✔️ يجب توزيع الأسئلة بالتساوي على جميع المواضيع.\n"
+ "❌ ممنوع العبارات الصحيحة/الخاطئة المنقولة حرفياً من المحتوى\n"
+ "❌ ممنوع الأسئلة التي يمكن حلها بالمنطق العام دون قراءة المحتوى\n"
+ "يجب اختيار درجة الصعوبة من متوسط وصعب وصعب جدا وكتابتها فى الdifficulty\n\n "
+ "⚠️ كل سؤال يجب أن يحتوي على الحقل التالي:"
+ "- topic_question_related_to: اسم الموضوع الفرعي المستخدم في السؤال\n"
+ "أخرج JSON مطابق لنموذج QuizOutput."
+ "Output must be as QuizOutput schema"
+ ),
+ expected_output="QuizOutput JSON",
+ output_json=QuizOutput,
+ agent=generate_quiz_agent,
+ async_execution=False,
+ # output_file=os.path.join(output_dir, "generated_quiz.json"),
+)
diff --git a/agents/design_phase/__init__.py b/agents/design_phase/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f528f010324d6f6dea7fb299ef8b1764c0b97aa1
--- /dev/null
+++ b/agents/design_phase/__init__.py
@@ -0,0 +1,5 @@
+from .keywoard_researcher import keyword_researcher_agent, keyword_researcher_task
+from .source_finder import search_engine_agent, search_engine_task
+from .scraper.extractor_bulit_in import scraping_built_in_agent, scraping_built_in_task
+from .scraper.extractor_bs4 import scraping_bs4_agent, scraping_bs4_task
+# from .scraper.extractor_crawlee import scraping_crawlee_agent, scraping_crawlee_task
diff --git a/agents/design_phase/keywoard_researcher.py b/agents/design_phase/keywoard_researcher.py
new file mode 100644
index 0000000000000000000000000000000000000000..478d5065d23ab6f2a9c023c5025687d2efbfaaf7
--- /dev/null
+++ b/agents/design_phase/keywoard_researcher.py
@@ -0,0 +1,50 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+from modules import llm
+#from schemas import SuggestedSearchQueries
+
+no_keywords = 25
+
+keyword_researcher_agent = Agent(
+ role="search queries recommendation agent",
+ goal="\n".join(
+ [
+ "To generate a set of structured and comprehensive search queries based on the topic {topic} "
+ "and the outline headings (main and sub-headings) provided from the outline task.",
+ "Queries should be varied, precise,relevant , and research-oriented.",
+ "For each heading and sub-heading, create multiple queries to help collect rich, relevant content from the web.",
+ "Queries must ensure coverage of the most important aspects of the topic, avoiding irrelevant or empty dimensions.",
+ "Avoid vague or overly generic queries.",
+ "Ensure queries reflect the scope of the outline, avoiding irrelevant or generic phrasing.",
+ "Strictly avoid generating queries related to religions, politics, or any biased/off-topic perspectives.",
+ ]
+ ),
+ backstory=(
+ "This agent acts as a scientific researcher and content strategist and instructional designer. "
+ "It takes the topic and its structured outline (headings + sub-headings) and expands them into precise, "
+ "targeted search queries. These queries are crafted to maximize coverage of the outline sections "
+ "and ensure the user can gather high-quality resources for each part."
+ ),
+ llm=llm,
+ verbose=True,
+)
+
+keyword_researcher_task = Task(
+ name="search queries recommendation task",
+ description="\n".join(
+ [
+ "Using the outline headings and sub-headings {outlines} for the topic {topic},",
+ "generate up to {no_keywords_Researcher_For_Each_Heading} short and precise search queries for each heading.",
+ "Each query must be short, complete, and precise, directly reflecting the heading or sub-heading it belongs to.",
+ "The aim is to cover the full breadth of the outline so that no important section is left without queries.",
+ "Queries should be research-oriented, avoiding vague or overly generic terms.",
+ "Important: All queries for the same heading must be unique and non-repetitive.",
+ "Do NOT generate queries that only differ by synonyms like 'concept' vs. 'definition'.",
+ "Instead, vary the focus (e.g., concept, benefits, methods, challenges, applications).",
+ "Strictly exclude any queries related to religion, politics, or biased/off-topic perspectives.",
+ ]
+ ),
+ expected_output="A JSON object containing a list of suggested search queries.",
+# output_json=SuggestedSearchQueries,
+ agent=keyword_researcher_agent,
+)
diff --git a/agents/design_phase/scraper/extractor_bs4.py b/agents/design_phase/scraper/extractor_bs4.py
new file mode 100644
index 0000000000000000000000000000000000000000..11ebcdae2a655f22ebb5a161809566f3d54b0299
--- /dev/null
+++ b/agents/design_phase/scraper/extractor_bs4.py
@@ -0,0 +1,96 @@
+from crewai import Agent, Task
+from modules import llm_g
+from tools import pdf_tool, scraping_tool
+from tools import WebScrapingToolBS4
+from schemas import UnitSubtopicOutputModel
+
+
+web_scraper = WebScrapingToolBS4(name="web_scraping_tool")
+
+scraping_bs4_agent = Agent(
+ role="Educational Content Scraping & Knowledge Extraction Agent",
+ goal="\n".join(
+ [
+ "Collect and extract complete, structured, and educationally valuable content "
+ "from Arabic and English websites and PDFs that i will give to you related to the course topic: {topic}.",
+ "Focus on content that match the course domain ({domain}), content type ({content_type}), "
+ "and audience ({audience}).",
+ "Prioritize materials that can serve as strong foundations for creating {material_type} "
+ "learning materials (conceptual, structural, procedural, and real-world).",
+ "Extract full text including all sections, examples, and details, ensuring high accuracy for Arabic text.",
+ "Assess each source’s credibility and educational relevance, ranking them by usefulness for course design.",
+ "Provide concise expert notes and recommendations that will assist curriculum developers and instructional designers "
+ "in selecting the best materials for building a complete learning unit.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "You are a specialized educational data researcher trained to explore, extract, and organize academic and professional content.",
+ "You excel at discovering high-quality Arabic and English resources that align with specific course development objectives.",
+ "Your mission is to help course designers collect trustworthy, pedagogically sound materials that will form the backbone of educational units.",
+ "You understand how to evaluate the quality, relevance, and credibility of both web pages and PDFs.",
+ "You are particularly skilled at preserving Arabic text integrity and extracting complete structured information for learning materials.",
+ ]
+ ),
+ llm=llm_g,
+ tools=[web_scraper],
+ verbose=True,
+)
+
+
+scraping_bs4_task = Task(
+ description="\n".join(
+ [
+ "Your task is to extract and organize full educational content from the following source:",
+ "",
+ "URL: {url}",
+ "Unit Title: {unit_title}",
+ "Subtopic Title: {subtopic_title}",
+ "Query Used: {query}",
+ "",
+ "This link is part of the course topic '{topic}' under the domain '{domain}'.",
+ "The extracted content should help create educational materials for the audience '{audience}', focusing on '{content_type}' learning goals.",
+ "",
+ "For the given URL:",
+ " - Extract the full title, structured text, and any available media (images, videos, audios, PDFs).",
+ " - Maintain the Arabic text structure and readability.",
+ " - Evaluate its reliability and educational value in relation to {material_type} material categories.",
+ " - Assign an agent recommendation rank (0–5) based on credibility and relevance.",
+ " - Provide short expert notes justifying the ranking and explaining how the content can contribute to the course design.",
+ "",
+ "Ensure no important content, examples, or explanations are omitted from extraction.",
+ "Output will be a json format with no task output or raw data only the formatted json dictionary.",
+ ]
+ ),
+ expected_output=(
+ "Return ONLY a valid Python dictionary.\n"
+ "- Do not include explanations, markdown, or code fences.\n"
+ "- The dictionary must be UTF-8 safe and directly usable in Python with ast.literal_eval.\n"
+ "- Keys must be wrapped in double quotes.\n\n"
+ "Format example:\n"
+ "{\n"
+ ' "unit_title": "من الفكرة إلى نموذج العمل: بناء الأساس الريادي",\n'
+ ' "subtopic_title": "مفهوم ريادة الأعمال وأهميتها الاقتصادية والاجتماعية",\n'
+ ' "query": "دور ريادة الأعمال في التنمية الاجتماعية",\n'
+ ' "parts": [\n'
+ " {\n"
+ ' "page_url": "https://example.com/page1",\n'
+ ' "title": "Understanding Entrepreneurship in the Arab World",\n'
+ ' "content": "Full educational content extracted from the site.",\n'
+ ' "img_url": ["https://example.com/image1.jpg"],\n'
+ ' "video_url": ["https://example.com/video1.mp4"],\n'
+ ' "audio_url": ["https://example.com/audio1.mp3"],\n'
+ ' "pdf_url": ["https://example.com/file1.pdf"],\n'
+ ' "agent_recommendation_rank": 4.8,\n'
+ ' "agent_recommendation_notes": "Rich Arabic content, relevant to conceptual materials."\n'
+ " }\n"
+ " ]\n"
+ "}\n\n"
+ "Make the output compatible with Python's ast library (use r1 = result.dict()['raw']; f_result = ast.literal_eval(r1)).\n"
+ "Ensure valid JSON syntax with no unterminated strings or extra text.\n"
+ "Output ONLY the dictionary — no thoughts, explanations, or markdown formatting."
+ "D"
+ ),
+ agent=scraping_bs4_agent,
+ output_json=UnitSubtopicOutputModel,
+)
diff --git a/agents/design_phase/scraper/extractor_bulit_in.py b/agents/design_phase/scraper/extractor_bulit_in.py
new file mode 100644
index 0000000000000000000000000000000000000000..42a78a13d20d55fc7667a7b4af82c6bfc24e7a8a
--- /dev/null
+++ b/agents/design_phase/scraper/extractor_bulit_in.py
@@ -0,0 +1,92 @@
+from crewai import Agent, Task
+from modules import llm_g
+from tools import pdf_tool, scraping_tool
+from schemas import UnitSubtopicOutputModel
+
+
+scraping_built_in_agent = Agent(
+ role="Educational Content Scraping & Knowledge Extraction Agent",
+ goal="\n".join(
+ [
+ "Collect and extract complete, structured, and educationally valuable content "
+ "from Arabic and English websites and PDFs that i will give to you related to the course topic: {topic}.",
+ "Focus on content that match the course domain ({domain}), content type ({content_type}), "
+ "and audience ({audience}).",
+ "Prioritize materials that can serve as strong foundations for creating {material_type} "
+ "learning materials (conceptual, structural, procedural, and real-world).",
+ "Extract full text including all sections, examples, and details, ensuring high accuracy for Arabic text.",
+ "Assess each source’s credibility and educational relevance, ranking them by usefulness for course design.",
+ "Provide concise expert notes and recommendations that will assist curriculum developers and instructional designers "
+ "in selecting the best materials for building a complete learning unit.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "You are a specialized educational data researcher trained to explore, extract, and organize academic and professional content.",
+ "You excel at discovering high-quality Arabic and English resources that align with specific course development objectives.",
+ "Your mission is to help course designers collect trustworthy, pedagogically sound materials that will form the backbone of educational units.",
+ "You understand how to evaluate the quality, relevance, and credibility of both web pages and PDFs.",
+ "You are particularly skilled at preserving Arabic text integrity and extracting complete structured information for learning materials.",
+ ]
+ ),
+ llm=llm_g,
+ tools=[pdf_tool, scraping_tool],
+ verbose=True,
+)
+
+
+scraping_built_in_task = Task(
+ description="\n".join(
+ [
+ "Your task is to extract and organize full educational content from the following source:",
+ "",
+ "URL: {url}",
+ "Unit Title: {unit_title}",
+ "Subtopic Title: {subtopic_title}",
+ "Query Used: {query}",
+ "",
+ "This link is part of the course topic '{topic}' under the domain '{domain}'.",
+ "The extracted content should help create educational materials for the audience '{audience}', focusing on '{content_type}' learning goals.",
+ "",
+ "For the given URL:",
+ " - Extract the full title, structured text, and any available media (images, videos, audios, PDFs).",
+ " - Maintain the Arabic text structure and readability.",
+ " - Evaluate its reliability and educational value in relation to {material_type} material categories.",
+ " - Assign an agent recommendation rank (0–5) based on credibility and relevance.",
+ " - Provide short expert notes justifying the ranking and explaining how the content can contribute to the course design.",
+ "",
+ "Ensure no important content, examples, or explanations are omitted from extraction.",
+ "Output will be a json format with no task output or raw data only the formatted json dictionary.",
+ ]
+ ),
+ expected_output=(
+ "Return ONLY a valid Python dictionary.\n"
+ "- Do not include explanations, markdown, or code fences.\n"
+ "- The dictionary must be UTF-8 safe and directly usable in Python with ast.literal_eval.\n"
+ "- Keys must be wrapped in double quotes.\n\n"
+ "Format example:\n"
+ "{\n"
+ ' "unit_title": "من الفكرة إلى نموذج العمل: بناء الأساس الريادي",\n'
+ ' "subtopic_title": "مفهوم ريادة الأعمال وأهميتها الاقتصادية والاجتماعية",\n'
+ ' "query": "دور ريادة الأعمال في التنمية الاجتماعية",\n'
+ ' "parts": [\n'
+ " {\n"
+ ' "page_url": "https://example.com/page1",\n'
+ ' "title": "Understanding Entrepreneurship in the Arab World",\n'
+ ' "content": "Full educational content extracted from the site.",\n'
+ ' "img_url": ["https://example.com/image1.jpg"],\n'
+ ' "video_url": ["https://example.com/video1.mp4"],\n'
+ ' "audio_url": ["https://example.com/audio1.mp3"],\n'
+ ' "pdf_url": ["https://example.com/file1.pdf"],\n'
+ ' "agent_recommendation_rank": 4.8,\n'
+ ' "agent_recommendation_notes": "Rich Arabic content, relevant to conceptual materials."\n'
+ " }\n"
+ " ]\n"
+ "}\n\n"
+ "Make the output compatible with Python's ast library (use r1 = result.dict()['raw']; f_result = ast.literal_eval(r1)).\n"
+ "Ensure valid JSON syntax with no unterminated strings or extra text.\n"
+ "Output ONLY the dictionary — no thoughts, explanations, or markdown formatting."
+ ),
+ agent=scraping_built_in_agent,
+ output_json=UnitSubtopicOutputModel,
+)
diff --git a/agents/design_phase/scraper/extractor_crawlee.py b/agents/design_phase/scraper/extractor_crawlee.py
new file mode 100644
index 0000000000000000000000000000000000000000..76b16e77ad48cb5c6f7830d5d7f7b455d8e4639e
--- /dev/null
+++ b/agents/design_phase/scraper/extractor_crawlee.py
@@ -0,0 +1,97 @@
+# from crewai import Agent, Task
+# from modules import llm_g
+# from tools import pdf_tool, scraping_tool
+# from tools import WebScrapingCrawleeTool
+# from schemas import UnitSubtopicOutputModel
+
+
+# web_scraper = WebScrapingCrawleeTool()
+
+# scraping_crawlee_agent = Agent(
+# role="Educational Content Scraping & Knowledge Extraction Agent",
+# goal="\n".join(
+# [
+# "Collect and extract complete, structured, and educationally valuable content "
+# "from Arabic and English websites and PDFs that i will give to you related to the course topic: {topic}.",
+ # "Focus on content that match the course domain ({domain}), content type ({content_type}), "
+ # "and audience ({audience}).",
+# "Prioritize materials that can serve as strong foundations for creating {material_type} "
+# "learning materials (conceptual, structural, procedural, and real-world).",
+# "Extract full text including all sections, examples, and details, ensuring high accuracy for Arabic text.",
+# "Assess each source’s credibility and educational relevance, ranking them by usefulness for course design.",
+# "Provide concise expert notes and recommendations that will assist curriculum developers and instructional designers "
+# "in selecting the best materials for building a complete learning unit.",
+# ]
+# ),
+# backstory="\n".join(
+# [
+# "You are a specialized educational data researcher trained to explore, extract, and organize academic and professional content.",
+# "You excel at discovering high-quality Arabic and English resources that align with specific course development objectives.",
+# "Your mission is to help course designers collect trustworthy, pedagogically sound materials that will form the backbone of educational units.",
+# "You understand how to evaluate the quality, relevance, and credibility of both web pages and PDFs.",
+# "You are particularly skilled at preserving Arabic text integrity and extracting complete structured information for learning materials.",
+# ]
+# ),
+# llm=llm_g,
+# tools=[web_scraper],
+# verbose=True,
+# )
+
+
+# scraping_crawlee_task = Task(
+# description="\n".join(
+# [
+# "Your task is to extract and organize full educational content from the following source:",
+# "",
+# "URL: {url}",
+# "Unit Title: {unit_title}",
+# "Subtopic Title: {subtopic_title}",
+# "Query Used: {query}",
+# "",
+# "This link is part of the course topic '{topic}' under the domain '{domain}'.",
+# "The extracted content should help create educational materials for the audience '{audience}', focusing on '{content_type}' learning goals.",
+# "",
+# "For the given URL:",
+# " - Extract the full title, structured text, and any available media (images, videos, audios, PDFs).",
+# " - Maintain the Arabic text structure and readability.",
+# " - Evaluate its reliability and educational value in relation to {material_type} material categories.",
+# " - Assign an agent recommendation rank (0–5) based on credibility and relevance.",
+# " - Provide short expert notes justifying the ranking and explaining how the content can contribute to the course design.",
+# "",
+# "Ensure no important content, examples, or explanations are omitted from extraction.",
+ # "Output will be a json format with no task output or raw data only the formatted json dictionary.",
+
+# ]
+# ),
+# expected_output=(
+# "Return ONLY a valid Python dictionary.\n"
+# "- Do not include explanations, markdown, or code fences.\n"
+# "- The dictionary must be UTF-8 safe and directly usable in Python with ast.literal_eval.\n"
+# "- Keys must be wrapped in double quotes.\n\n"
+# "Format example:\n"
+# "{\n"
+# ' "unit_title": "من الفكرة إلى نموذج العمل: بناء الأساس الريادي",\n'
+# ' "subtopic_title": "مفهوم ريادة الأعمال وأهميتها الاقتصادية والاجتماعية",\n'
+# ' "query": "دور ريادة الأعمال في التنمية الاجتماعية",\n'
+# ' "parts": [\n'
+# " {\n"
+# ' "page_url": "https://example.com/page1",\n'
+# ' "title": "Understanding Entrepreneurship in the Arab World",\n'
+# ' "content": "Full educational content extracted from the site.",\n'
+# ' "img_url": ["https://example.com/image1.jpg"],\n'
+# ' "video_url": ["https://example.com/video1.mp4"],\n'
+# ' "audio_url": ["https://example.com/audio1.mp3"],\n'
+# ' "pdf_url": ["https://example.com/file1.pdf"],\n'
+# ' "agent_recommendation_rank": 4.8,\n'
+# ' "agent_recommendation_notes": "Rich Arabic content, relevant to conceptual materials."\n'
+# " }\n"
+# " ]\n"
+# "}\n\n"
+# "Make the output compatible with Python's ast library (use r1 = result.dict()['raw']; f_result = ast.literal_eval(r1)).\n"
+# "Ensure valid JSON syntax with no unterminated strings or extra text.\n"
+# "Output ONLY the dictionary — no thoughts, explanations, or markdown formatting."
+# ),
+# agent=scraping_crawlee_agent,
+# output_json=UnitSubtopicOutputModel,
+# )
+# #
\ No newline at end of file
diff --git a/agents/design_phase/source_finder.py b/agents/design_phase/source_finder.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a8d3a232a3cc896780a3ca2df932572400fc92e
--- /dev/null
+++ b/agents/design_phase/source_finder.py
@@ -0,0 +1,77 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+from modules import llm_oss
+from crewai_tools import SerperDevTool
+from schemas import SearchEngineOutput
+from tools import URLValidatorTool
+
+# --- Tool ---
+search_tool = SerperDevTool()
+url_validate_tool = URLValidatorTool(name="url_validator")
+
+# --- Agent Definition ---
+search_engine_agent = Agent(
+ role="Search and Validation agent",
+ goal="\n".join(
+ [
+ "Search for diverse, high-quality, and reliable information related to {topic} using the suggested search queries.",
+ "Prioritize **scholarly and educational resources**: academic journals, books, research articles, and trusted institutional websites and our trusted sites we know: {TRUSTED_SITES}.",
+ "Include Arabic sources when contextually valuable, but prioritize English academic sources for broader coverage.",
+ "Ensure all results are concise, relevant, and aligned with the outline headings to directly support course design and educational content.",
+ "For each query, return at most {no_links} results with structured metadata (title, url, content summary, score, search_query).",
+ "Validate URLs before retrieving them and if it is not valid dont retieve",
+ ]
+ ),
+ backstory=(
+ "This agent acts like a scientific researcher and educational content curator."
+ "It executes the generated queries and gathers high-value, trustworthy information."
+ "The agent is trained to filter out irrelevant, commercial, or low-quality content, ensuring that "
+ "only academic and pedagogically useful resources are kept."
+ "for building interactive e-learning content are retrieved."
+ "It balances global knowledge with local cultural enrichment by including both English and Arabic sources."
+ "Uses Serper search and validates each found URL."
+ ),
+ verbose=True,
+ llm=llm_oss,
+ tools=[search_tool, url_validate_tool],
+ allow_delegation=False,
+)
+
+# --- Task Definition ---
+search_engine_task = Task(
+ name="Academic Web Search",
+ description="\n".join(
+ [
+ "The task is to search the web for relevant and reliable resources about {topic} using the suggested search queries.",
+ "You must collect results from multiple queries to ensure diversity of perspectives and sources.",
+ "Here are the queries you can use to search:",
+ "{queries}",
+ "use unit title: {unit_title} and subtopic title: {subtopic_title} to complete the output and search correctly for each query.",
+ "For each query, retrieve at least 1 link and a maximum of {no_links} links only.",
+ "Prioritize scholarly, academic, and educational resources (journals, books, institutional websites).",
+ "Filter out irrelevant, suspicious, or low-quality results (e.g., personal blogs, spam, commercial ads).",
+ "Apply score filtering: ignore results with a confidence score lower than {score_th}.",
+ "The final results will serve as the knowledge base for building trusted, high-quality content, ",
+ "with a focus on supporting the course’s educational objectives and cultural enrichment goals.",
+ "with a focus on supporting the course’s educational objectives and cultural enrichment goals.",
+ "Get sites that newer than 2021.",
+ "Validate URLs before retrieving them and if it is not valid dont retieve",
+
+ ]
+ ),
+ expected_output=(
+ "Return ONLY a valid UTF-8 safe Python dictionary (no markdown, no code blocks). "
+ "It must be directly parsable with ast.literal_eval. Use this format:\n\n"
+ "{\n"
+ ' "unit_title": "...",\n'
+ ' "subtopic_title": "...",\n'
+ ' "query": "...",\n'
+ ' "results": [\n'
+ ' {"url": "...", "title": "...", "content": "...", "score": 0.91}\n'
+ " ]\n"
+ "}"
+ ),
+ output_json=SearchEngineOutput,
+ agent=search_engine_agent,
+ output_file="search_results.json",
+)
diff --git a/agents/final_outliners/__init__.py b/agents/final_outliners/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..20b25dc9ecf9ff2827506065d321e33910121152
--- /dev/null
+++ b/agents/final_outliners/__init__.py
@@ -0,0 +1,4 @@
+from .subtopics_generator import subtopics_generator_agent, subtopics_generation_task
+from .validator import validator_agent, validation_task
+# from .units_langchain import units_langchain_agent
+from .units_langchain_1v import units_langchain1_agent
\ No newline at end of file
diff --git a/agents/final_outliners/subtopics_generator.py b/agents/final_outliners/subtopics_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..356fa5ef253755f48c82c5179041836dff500249
--- /dev/null
+++ b/agents/final_outliners/subtopics_generator.py
@@ -0,0 +1,132 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm_5m, llm_g
+from schemas import FullCurriculumStructure
+
+
+def subtopics_generator_agent():
+ model = llm_g()
+ return Agent(
+ role="Arabic Educational Subtopic Generator (Subtopic Developer)",
+ goal=(
+ "Analyze the provided metadata ({topic}, {domain}, {audience}, {content_type}, {material_type}) "
+ "along with the CurriculumStructure (containing the main concept, General_objectives_of_the_plan, and list of units and their details). "
+ "For each unit — based on its title and details — generate list of coherent and progressive Arabic subtopics (axes). "
+ "These subtopics should represent a logical and educational flow from foundational understanding "
+ "to advanced application and creativity. "
+ "Each unit's subtopic should represent a specific stage of learning progression — starting from basic knowledge acquisition "
+ "and moving toward critical thinking and creative application. "
+ ## ADD
+ "Example:"
+ "- Unit: التفكير التصميمي وحل المشكلات"
+ "- Given Subtopics:"
+ " • ماذا يعنى حل المشكلة؟"
+ " • 4 خطوات لحل المشكلة"
+ " • الفرق بين التفكير التحليلي والتصميمي في حل المشكلات"
+ " • نهج التفكير التصميمي لحل المشكلات"
+ " • نماذج تطبيقية ناجحة في حل المشكلات بالتفكير التصميمي"
+ "- Observation: The first two are introductory — essential for understanding the later applied parts."
+ ## ADD
+ "Finally, ensure that all generated subtopics comply with the approved Arabic educational titling standards:\n"
+ "- Titles must be clear, direct, and precise, avoiding ambiguous or poetic phrasing.\n"
+ "- Avoid dual or compound titles; use a single, focused phrasing.\n"
+ "- Each title must reflect its actual educational content accurately.\n"
+ # "- Limited creativity is acceptable, but without exaggeration or metaphorical obscurity.\n"
+ "- Always adapt the title to the target audience’s cultural and cognitive level.\n"
+ "These standards ensure the linguistic clarity and educational value of all generated subtopics."
+ "Ensure that the subtopics are written as Arabic educational subheadings that align with the unit’s focus, "
+ "support conceptual growth, and maintain thematic coherence across the curriculum."
+ "Ensure all subtopics are contextually relevant to the unit's focus and contribute to the learner's comprehensive understanding."
+ ),
+ backstory=(
+ "You are a senior Arabic curriculum designer and learning progression specialist. "
+ # "You possess deep expertise in Arabic pedagogy and cognitive development frameworks such as Bloom’s Taxonomy. "
+ "You skillfully expand each educational unit into coherent Arabic subtopics that reflect a logical learning progression — "
+ "starting from basic understanding and moving toward higher-order thinking and creative application. "
+ "Each subtopic builds upon the previous one to form a cohesive and culturally relevant learning journey. "
+ "Your designs prioritize conceptual clarity, educational depth, and alignment with Arabic academic standards."
+ "You also ensure that each generated subtopic is research-backed and can be supported by credible educational materials available online, enabling later integration with content retrieval systems."
+ ## ADD
+ "You strictly follow the approved Arabic educational title formulation standards, ensuring clarity, precision, and appropriateness for the learner’s level."
+ ),
+ output_format=(
+ "Return valid JSON strictly following this structure:\n"
+ "{\n"
+ " 'main_concept': '...',\n"
+ " 'units': [\n"
+ " {\n"
+ " 'unit_number': 1,\n"
+ " 'title': 'الوحدة الأولى: ...',\n"
+ " 'focus': '...',\n"
+ " 'axes': [\n"
+ " {'axis_number': 1, 'title': '...', 'purpose': '...'},\n"
+ " {'axis_number': 2, 'title': '...', 'purpose': '...'},\n"
+ " {'axis_number': 3, 'title': '...', 'purpose': '...'},\n"
+ " {'axis_number': 4, 'title': '...', 'purpose': '...'},\n"
+ " {'axis_number': 5, 'title': '...', 'purpose': '...'}\n"
+ " ]\n"
+ " }, ...\n"
+ " ]\n"
+ "}"
+ ),
+ # llm=llm_open_c35,
+ llm=model,
+ allow_delegation=False,
+ verbose=True,
+ reasoning=True,
+ max_iter=100,
+)
+
+# ============================================================
+# 🧩 3. Axis Generation Task
+# ============================================================
+
+def subtopics_generation_task(subtopics_generator_agent):
+ return Task(
+ description=(
+ "## GOAL\n"
+ "Expand each educational unit from the given file into number of structured Arabic subtopics: {units}. "
+ # "Each axis should develop the learner’s understanding progressively — starting with remembering, "
+ # "then understanding, applying, analyzing, and finally creating.\n"
+ "Each subtopic should represent a cognitive development stage — moving from foundational understanding to applied mastery.\n\n"
+ "## CONTEXT\n"
+ # "You are provided with a units_agent_conceptual JSON (containing the main concept, related concepts, and list of units). "
+ "You are provided with a CurriculumStructure JSON (containing the main concept, General_objectives_of_the_plan, and list of units and their details). "
+ # "Each unit includes a title and conceptual focus.\n\n"
+ "## STEPS\n"
+ "1. Read the CurriculumStructure carefully to understand the hierarchy and conceptual logic.\n"
+ "2. For each unit:\n"
+ " - Identify its title and details.\n"
+ " - Generate list of progressive subtopics that unfold logically.\n"
+ " - Each subtopic must include:\n"
+ " • 'subtopic_number': numerical order of the subtopic in the unit.\n"
+ " • 'title': Arabic title that feels like a subheading in a textbook.\n"
+ " • 'purpose': one-sentence explanation of the educational goal behind that subtopic.\n\n"
+ "3. For each generated subtopic\n"
+ " - Prefer subtopics that are well-established in educational or academic literature.\n"
+ " - Avoid overly niche or abstract titles that would lack sufficient learning resources.\n\n"
+ ## ADD
+ "4. Validate that each subtopic:\n"
+ " - Aligns with Arabic educational title standards (clarity, focus, precision, and appropriateness).\n"
+ " - Avoids dual titles, poetic phrasing, or abstract metaphors.\n\n"
+ "5. **Subtopics Title Quality & Language Validation**\n"
+ " - Each subtopic title is the learner’s first point of contact with the concept, so ensure the following:\n"
+ " Title length: concise (4–8 words preferred).\n"
+ " Clear and contextually linked to its unit or topic.\n"
+ " Written in tone appropriate for {audience}.\n"
+ " Avoids punctuation marks (– , ; : . ! ? , /) except for simple questions.\n"
+ " Represents one coherent idea — avoid compound or dual phrasing.\n"
+ " Avoids activity-based terms like 'ورشة عمل' or 'نشاط'.\n"
+ " Sounds realistic, teachable, and suitable for Arabic educational content.\n"
+ " can be in form of short sentence or a question\n\n"
+ "## NOTES\n"
+ # "- Make sure the subtopics flow naturally, covering introduction, comprehension, practice, and innovation.\n"
+ # "- The 5 axes should reflect a natural flow following Bloom’s taxonomy: Remember → Understand → Apply → Analyze → Create.\n"
+ "- Ensure the titles sound academic, culturally appropriate, and pedagogically progressive.\n"
+ "- Return the result as a valid FullCurriculumStructure JSON containing all units with their subtopics."
+ ),
+ expected_output="A FullCurriculumStructure JSON object containing all units and their respective list of subtopics each.",
+ agent=subtopics_generator_agent,
+ output_json=FullCurriculumStructure,
+)
diff --git a/agents/final_outliners/units_langchain.py b/agents/final_outliners/units_langchain.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd4aa9745cb74228ad07e2ad56ba2f9812f87640
--- /dev/null
+++ b/agents/final_outliners/units_langchain.py
@@ -0,0 +1,136 @@
+# # from langchain.agents import create_tool_calling_agent, AgentExecutor
+# # from langchain.prompts import ChatPromptTemplate
+# # from modules import model, llm_g
+# # import json
+# # import re
+# # import pandas as pd
+
+
+# # def units_langchain_agent(topic: str, units_number: int):
+# # # الخطوة 1: نطلب من llm_g إنشاء Markdown plan
+# # result = llm_g.call(
+# # f"Create a structured {units_number}-unit study plan for the topic [{topic}]"
+# # )
+
+# # # الخطوة 2: الـ System Prompt الخاص بالاستخراج
+# # system_prompt = """
+# # You will receive Markdown text representing a study plan.
+# # Extract structured data and return it strictly in this JSON format:
+
+# # {{
+# # "topic": "",
+# # "General_objectives_of_the_plan": ["string", "string", ...],
+# # "total_units": ,
+# # "units": [
+# # {{
+# # "unit_number": 1,
+# # "unit_title": "string",
+# # "description": "string",
+# # "unit_objectives": ["string", "string", ...],
+# # "unit_main_topics": ["string", "string", ...]
+# # }},
+# # ...
+# # ]
+# # }}
+
+# # Output **only valid JSON**, no explanations, markdown, or extra text.
+# # """
+
+# # # الخطوة 3: إنشاء prompt فيه متغير agent_scratchpad المطلوب
+# # prompt = ChatPromptTemplate.from_messages(
+# # [
+# # ("system", system_prompt),
+# # ("user", "{input}"),
+# # ("assistant", "{agent_scratchpad}"), # << الإضافة المطلوبة
+# # ]
+# # )
+
+# # # الخطوة 4: إنشاء الـ Agent
+# # tools = [] # مفيش Tools هنا
+# # agent = create_tool_calling_agent(model, tools, prompt=prompt)
+
+# # # الخطوة 5: تنفيذ الـ Agent
+# # agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
+# # response = agent_executor.invoke({"input": result, "agent_scratchpad": ""})
+
+# # # الخطوة 6: استخراج النتيجة
+# # raw_output = response.get("output", "").strip()
+
+# # # الخطوة 7: تنظيف وتحويل JSON
+# # try:
+# # structured_data = json.loads(raw_output)
+# # except json.JSONDecodeError:
+# # cleaned = re.sub(r"```json|```", "", raw_output).strip()
+# # structured_data = json.loads(cleaned)
+
+# # return structured_data
+
+
+# from modules import model, llm_g
+# import json
+# import re
+# from langchain.agents import initialize_agent, AgentType
+
+# # from langchain.agents import create_agent
+
+
+# def units_langchain1_agent(topic: str, units_number: int):
+# llm = llm_g()
+# # الخطوة 1: نطلب من llm_g إنشاء Markdown plan
+# result = llm.call(
+# f"Create a structured {units_number}-unit study plan for the topic [{topic}] focuses on logical sequencing and educational activities without delving into scientific or technical details, The plan should be similar to a training plan that can be presented in a workshop or short course."
+# )
+
+# # الخطوة 2: الـ System Prompt الخاص بالاستخراج
+# system_prompt = """
+# extract structured data from Markdown text you will be given.
+
+# The JSON should have this exact structure:
+# {
+# "topic": "",
+# "General_objectives_of_the_plan": ["string", "string", ...]
+# "total_units": ,
+# "units": [
+# {
+# "unit_number": 1,
+# "unit_title": "string",
+# "description": "string",
+# "unit_objectives": ["string", "string", ...],
+# "unit_main_topics": ["string", "string", ...]
+# },
+# ...
+# ]
+# }
+
+# NOTE:
+# if any descriptions are missing from the given file you can generate them after understanding the context.
+
+# Output **only valid JSON**, no explanations, markdown, or extra text.
+# """
+
+# # agent = create_agent(
+# # model=model,
+# # system_prompt=system_prompt,
+# # )
+# model_open = model()
+# agent = initialize_agent(
+# system_prompt=system_prompt,
+# llm=model_open,
+# agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
+# verbose=True,
+# )
+
+# response = agent.invoke({"messages": [{"role": "user", "content": result}]})
+
+# #######################
+# # الخطوة 6: استخراج النتيجة
+# raw_output = response["messages"][1].content.strip()
+
+# # الخطوة 7: تنظيف وتحويل JSON
+# try:
+# structured_data = json.loads(raw_output)
+# except json.JSONDecodeError:
+# cleaned = re.sub(r"```json|```", "", raw_output).strip()
+# structured_data = json.loads(cleaned)
+
+# return structured_data
diff --git a/agents/final_outliners/units_langchain_1v.py b/agents/final_outliners/units_langchain_1v.py
new file mode 100644
index 0000000000000000000000000000000000000000..9025dd0c169833fbee723ea0ac54de2af869a7de
--- /dev/null
+++ b/agents/final_outliners/units_langchain_1v.py
@@ -0,0 +1,69 @@
+from modules import model, llm_g
+import json
+import re
+from langchain_core.messages import SystemMessage, HumanMessage
+
+def units_langchain1_agent(topic: str, units_number: int):
+
+ # ---------- Step 1 : Generate Markdown Plan ----------
+ llm = llm_g()
+
+ result = llm.call(
+ f"""
+Create a structured {units_number}-unit study plan for the topic [{topic}].
+
+Focus on logical sequencing and educational activities without deep technical details.
+The plan should resemble a training plan suitable for a workshop or short course.
+
+Return the plan in clear Markdown.
+"""
+ )
+
+ # ---------- Step 2 : System Prompt for JSON extraction ----------
+ system_prompt = """
+Extract structured data from the Markdown text you will receive.
+
+Return JSON with this exact structure:
+
+{
+ "topic": "",
+ "General_objectives_of_the_plan": ["string", "string"],
+ "total_units": ,
+ "units": [
+ {
+ "unit_number": 1,
+ "unit_title": "string",
+ "description": "string",
+ "unit_objectives": ["string"],
+ "unit_main_topics": ["string"]
+ }
+ ]
+}
+
+Rules:
+- If descriptions are missing you may generate them from context
+- Output ONLY valid JSON
+- No markdown
+- No explanations
+"""
+
+ # ---------- Step 3 : Call Gemini via LangChain ----------
+ llm_model = model()
+
+ response = llm_model.invoke(
+ [
+ SystemMessage(content=system_prompt),
+ HumanMessage(content=result),
+ ]
+ )
+
+ raw_output = response.content.strip()
+
+ # ---------- Step 4 : Clean JSON ----------
+ try:
+ structured_data = json.loads(raw_output)
+ except json.JSONDecodeError:
+ cleaned = re.sub(r"```json|```", "", raw_output).strip()
+ structured_data = json.loads(cleaned)
+
+ return structured_data
diff --git a/agents/final_outliners/validator.py b/agents/final_outliners/validator.py
new file mode 100644
index 0000000000000000000000000000000000000000..273a21f6f5fc6717a44e5672b8d0e1723306f7fc
--- /dev/null
+++ b/agents/final_outliners/validator.py
@@ -0,0 +1,142 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm_5m, llm_g
+from schemas import ValidatedCurriculumOutput, validated_parser
+from functools import cache
+
+def validator_agent():
+ model = llm_g()
+ return Agent(
+ role="Arabic Educational Validator (Curriculum Quality & Integrity Specialist)",
+ goal=(
+ "Ensure that all educational units and subtopics are conceptually complete, logically sequenced, linguistically refined, "
+ "and pedagogically sound for Arabic learners. Validate and enhance each unit's structure to maintain educational coherence "
+ "and clarity while preserving Arabic authenticity. Ensure all titles are in Arabic only. and try to include the notes given in the structure."
+ ),
+ backstory=(
+ "You are a senior Arabic educational content validator and curriculum refinement expert. "
+ "You specialize in verifying conceptual completeness, depth, and sequencing of educational materials. "
+ "You understand Bloom’s taxonomy and Arabic pedagogical standards deeply. "
+ "You ensure all subtopics form a coherent, realistic, and progressive learning journey for the audience. "
+ "You maintain academic rigor and cultural authenticity while improving clarity and depth."
+ ),
+ output_format=(
+ "Return a valid JSON with the following structure:\n"
+ "{\n"
+ " 'main_concept': '...',\n"
+ " 'General_objectives_of_the_plan': '...',\n"
+ " 'validated_units': [\n"
+ " {\n"
+ " 'unit_number': 1,\n"
+ " 'title': '...',\n"
+ " 'focus': '...',\n"
+ " 'validated_axes': [\n"
+ " {\n"
+ " 'axis_number': 1,\n"
+ " 'original_title': '...',\n"
+ " 'validated_title': '...',\n"
+ " 'original_purpose': '...',\n"
+ " 'validated_purpose': '...',\n"
+ " 'status': 'kept' | 'rephrased' | 'added' | 'removed'\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}"
+ ),
+ # llm=llm_open_c35,
+ llm=model,
+ allow_delegation=False,
+ verbose=True,
+ reasoning=True,
+ max_iter=100,
+ cache=False,
+)
+
+def validation_task(validator_agent):
+ return Task(
+ description=(
+ "Validate, refine, and enhance all generated educational units and their subtopics (only those needing improvement). "
+ "Ensure conceptual completeness, logical sequencing, and pedagogical depth across all units.\n\n"
+ "===================================================\n"
+ "## INPUT\n"
+ "You will be given a FullCurriculumStructure JSON from axis_generator_agent and details: {units}. "
+ "NOTES may also be provided {note}. These notes contain additional instructions or required new content. "
+ "so think how to achieve this within the educational plan, should you add new subtopic or new unit with new subtopic or modify anything(sure without deleting), "
+ "The agent must interpret the notes and add the required new subtopics or axes to the appropriate unit. "
+ "Example: If the note says 'تناول الاستخدامات الحديثة لتحليل البيانات في محور واحد', "
+ "you must add a new subtopic titled 'الاستخدامات الحديثة لتحليل البيانات' or any academically suitable Arabic title, "
+ "place it in the correct unit, and mark its status as 'added'.\n\n"
+ "===================================================\n"
+ "PRIMARY OBJECTIVE\n"
+ "===================================================\n"
+ "Ensure each unit exhibits:\n"
+ "1- Full conceptual and pedagogical integration.\n"
+ "2- Logical sequencing of ideas.\n"
+ "3- Arabic educational clarity and realism.\n"
+ "4- Comprehensive coverage of all described relations, aspects, and intentions.\n"
+ "5- Ensure the unit name best expresses its content in professional Arabic.\n"
+ "6- Avoid punctuation marks (– , ; : . ! ? , /) except for simple questions.\n"
+ "7- If removing punctuation affects grammar, enhance the title for natural Arabic style.\n\n"
+ "===================================================\n"
+ "PHASE 1 — COMPREHENSIVENESS & DEPTH ANALYSIS\n"
+ "===================================================\n"
+ "1. Analyze all subtopics for each unit and unit details.\n"
+ "2. Identify missing conceptual foundations (definitions, context, prerequisites, motivation).\n"
+ "3. Add any necessary **introductory subtopics** with clear Arabic titles and purposes.\n"
+ "4. Detect and remove any redundant or overlapping axes.\n\n"
+ "===================================================\n"
+ "PHASE 2 — INTEGRATION & SEQUENCING VALIDATION\n"
+ "===================================================\n"
+ "1. Ensure smooth conceptual progression from basic to advanced.\n"
+ "2. Merge or rephrase redundant axes while preserving educational intent.\n"
+ "3. Add **bridging subtopics** if conceptual jumps exist.\n"
+ "4. Reorder axes if needed to restore logical flow.\n\n"
+ "===================================================\n"
+ "PHASE 3 — REALISM & COVERAGE VALIDATION\n"
+ "===================================================\n"
+ "1. Confirm every conceptual aspect in the unit’s focus and all details is represented.\n"
+ "2. Ensure subtopics are realistic and pedagogically valid for the target audience.\n"
+ "3. Add missing real-world or practical dimensions.\n"
+ "4. Maintain natural, professional Arabic phrasing.\n\n"
+ "===================================================\n"
+ "PHASE 4 — SUBTOPICS TITLE QUALITY & LANGUAGE VALIDATION\n"
+ "===================================================\n"
+ "4. Validate that each Subtopic:\n"
+ " - Aligns with Arabic educational title standards (clarity, focus, precision, and appropriateness).\n"
+ " - Avoids dual titles, poetic phrasing, or abstract metaphors.\n\n"
+ "5. **Subtopics Title Quality & Language Validation**\n"
+ " - Title length: concise (4–8 words preferred).\n"
+ " - Clear and contextually linked to its unit.\n"
+ " - Tone appropriate for {audience}.\n"
+ " - Avoids punctuation marks except for simple questions.\n"
+ " - Represents one coherent idea, not compound.\n"
+ " - Avoids activity-based terms like 'ورشة عمل' or 'نشاط'.\n"
+ " - Sounds realistic, teachable, and suitable for Arabic educational content.\n\n"
+ "===================================================\n"
+ "PHASE 4.1 — ARABIC LANGUAGE INTEGRITY ENFORCEMENT\n"
+ "===================================================\n"
+ "1. Ensure that all titles (unit and subtopic) are written entirely in Arabic script.\n"
+ "2. If a title contains any Latin (English) letters, numerals, or symbols, rephrase it fully into correct Modern Standard Arabic.\n"
+ "3. Maintain original meaning and clarity when translating or rephrasing into Arabic.\n"
+ "4. Titles must not contain any transliterations (e.g., 'Entrepreneurship', 'AI', 'Design Thinking'). Replace them with Arabic equivalents.\n"
+ "5. Reject any title that cannot be made purely Arabic, and provide a suitable Arabic substitute aligned with educational context.\n\n"
+ "===================================================\n"
+ "PHASE 5 — OUTPUT STRUCTURE\n"
+ "===================================================\n"
+ "Return validated curriculum in JSON format with units, subtopics, and validation status.\n\n"
+ "===================================================\n"
+ "## NOTES\n"
+ "- Keep phrasing in professional Modern Standard Arabic.\n"
+ "- Avoid dual, poetic, or abstract titles.\n"
+ "- Ensure all outputs are grammatically correct and stylistically natural Arabic.\n"
+ "- Titles must not include any English or foreign words."
+ "- don't let the added notes destroy any of the curriculum structur only add what is needed."
+ ),
+ # guardrail="",
+ expected_output="A JSON object showing validated units and subtopics with Arabic-only titles.",
+ output_json=ValidatedCurriculumOutput,
+ output_parser=validated_parser,
+ agent=validator_agent,
+)
diff --git a/agents/outliner_phase/Deep_Semantic_Topics_Generator_1.py b/agents/outliner_phase/Deep_Semantic_Topics_Generator_1.py
new file mode 100644
index 0000000000000000000000000000000000000000..813791e87ee900fbed794c644dc84470da6c4481
--- /dev/null
+++ b/agents/outliner_phase/Deep_Semantic_Topics_Generator_1.py
@@ -0,0 +1,121 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+from schemas import CurriculumOutline, DeepSemanticTopicsOutput
+
+# ---------------------------
+# === Agent 1: Deep Semantic Topics Generator (Full Coverage + Metadata Adaptive) ===
+# ---------------------------
+
+def research_agent():
+ model = llm()
+ return Agent(
+ role="Deep Semantic Topics Generator (Educational Research Agent)",
+ goal="\n".join(
+ [
+ "Generate as many interconnected and realistic Arabic topics as possible for the curriculum title: {topic}.",
+ "Do NOT divide topics into units — just produce a comprehensive standalone list of high-quality topics.",
+ "Your mission is to achieve *maximum conceptual and practical coverage* of the topic: cover every visible and implicit meaning embedded in the title: {topic}.",
+ "Interpret the topic deeply and explore all related sub-concepts, tools, methods, applications, personal skills, frameworks, real-world examples, and future trends.",
+ "No aspect of the topic should remain uncovered — ensure total thematic coverage from theory to practice.",
+ # === Adaptation & Metadata awareness ===
+ "Always adapt to metadata: domain ({domain}), content_type ({content_type}), audience ({audience}), material_type ({material_type}).",
+ "Adjust tone, complexity, and depth according to the audience and domain type.",
+ "Apply DNA methodology explicitly in topic design:",
+ "- material_type:",
+ "-- Conceptual: theories, principles, abstract knowledge.",
+ "-- Procedural: step-by-step instructions or methods.",
+ "-- Structural: frameworks, models, or system views.",
+ "-- Personal: learner reflection, skills, or self-development aspects.",
+ "-- Realistic: real-world examples, applications, or case studies.",
+ "- content_type:",
+ "-- Educational → for structured learning (e.g., lessons, modules).",
+ "-- Awareness → for informative or awareness-raising purposes (e.g., campaigns, workshops).",
+ "-- Training → for hands-on skill development (e.g., exercises, applied learning).",
+ # === Learning progression ===
+ "Ensure logical educational progression throughout the topics:",
+ " 1️⃣ Start with conceptual understanding (definitions, foundations, importance).",
+ " 2️⃣ Then practical tools and applications (methods, workflows, tools).",
+ " 3️⃣ Then analysis and real-world case studies (evaluation, lessons learned).",
+ " 4️⃣ End with strategies, integration, and innovation (advanced synthesis, policies, or future directions).",
+ # === Title & Content validation ===
+ "Each topic must be realistic and searchable in Arabic or bilingual educational sources.",
+ "Before finalizing each topic, mentally confirm that real Arabic educational content exists online for it.",
+ "Reject or replace any vague, repetitive, or non-educational topics.",
+ "Avoid vague or redundant points — every topic must be unique and non-overlapping.",
+ # === Arabic educational title standards ===
+ "Follow Arabic educational title standards strictly:",
+ " - Clear, concise, and direct phrasing (no metaphors or poetic language).",
+ " - Titles should be between 4–7 words long.",
+ " - Represent a clear learning focus, suitable for the target audience ({audience}).",
+ " - Example good: مهارات التفكير النقدي واتخاذ القرار",
+ " - Example bad: رحلة العقل نحو التفكير النقدي وصناعة القرار",
+ # === Output schema ===
+ "For each topic, provide the following JSON fields exactly:",
+ " - title: Arabic, concise and direct",
+ " - description: 1–2 lines Arabic summarizing the topic",
+ " - dna: one of [Conceptual, Procedural, Structural, Personal, Realistic] and [Educational, Awareness, Training]",
+ " - suggested_unit: integer (1–4) showing depth progression (1=basic → 4=advanced)",
+ " - search_terms: 3–6 Arabic keywords relevant to the topic",
+ " - source: optional Arabic or bilingual educational source name/title (if known)",
+ # === Output constraints ===
+ "Output must be a valid JSON list (no commentary, no explanations).",
+ "List must be ordered by suggested_unit (1 → 4) to reflect gradual learning progression.",
+ ]
+ ),
+ backstory="\n".join(
+ [
+ "You are a senior educational researcher and curriculum architect with deep expertise in Arabic educational design and semantic topic analysis.",
+ "You deeply interpret the input topic — uncovering both its explicit and implicit meanings to ensure total thematic coverage.",
+ "You create coherent, realistic, and pedagogically structured topic sets that form a logical educational progression.",
+ "Each topic you design is grounded in actual Arabic or bilingual educational resources, ensuring that every subject can be realistically taught or studied.",
+ "You think step by step before finalizing outputs — validating realism, logical sequence, and online content availability.",
+ "Your work directly feeds the downstream Outline Agent, so clarity, precision, and educational completeness are essential in every topic you produce.",
+ ]
+ ),
+ allow_delegation=False,
+ llm=model,
+ reasoning=True,
+ verbose=True,
+ max_reasoning_attempts=4,
+ max_iter=100,
+)
+
+# ---------------------------
+# === Task 1: Generate Deep & Comprehensive Topics ===
+# ---------------------------
+
+def research_task(research_agent):
+ return Task(
+ description="\n".join(
+ [
+ "Generate a comprehensive, realistic, and logically structured list of Arabic topics for {topic}.",
+ "Ensure full semantic coverage — address both the explicit and implicit meanings of the topic title to cover all relevant dimensions and perspectives.",
+ "Include topics that collectively span all DNA dimensions and metadata parameters: content_type ({content_type}) and material_type ({material_type}).",
+ "Each topic must be unique, clear, and pedagogically meaningful — avoiding repetition, overlap, or vague expressions.",
+ "All topics must be realistic and supported by potential Arabic or bilingual educational resources available online.",
+ "Ensure educational progression: begin with conceptual foundations and definitions, then move through methods and tools, practical applications, case studies, and finally strategic or innovative insights.",
+ "Maintain alignment with Arabic educational title standards: concise, direct, single-part titles with clear learning focus.",
+ "Output must be a valid JSON list following the schema below — no explanations, introductions, or extra commentary.",
+ ]
+ ),
+ expected_output=(
+ "A valid JSON list ordered by suggested_unit ascending:\n"
+ "[\n"
+ " {\n"
+ ' "title": "string (Arabic)",\n'
+ ' "description": "string (1–2 lines in Arabic)",\n'
+ ' "dna": "Conceptual|Procedural|Structural|Personal|Realistic",\n'
+ ' "suggested_unit": 1|2|3|4,\n'
+ ' "search_terms": ["string (Arabic keyword)", ...],\n'
+ ' "source": "string (optional)"\n'
+ " }, ...\n"
+ "]\n"
+ "The output must be valid JSON, without markdown formatting or code blocks."
+ ),
+ params={"min_topics": 10, "max_topics": 30}, # expand to ensure deeper coverage
+ output_json=DeepSemanticTopicsOutput,
+ # output_file=os.path.join(output_dir, "deep_semantic_topics.json"),
+ agent=research_agent,
+)
diff --git a/agents/outliner_phase/__init__.py b/agents/outliner_phase/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f146290fa981fe93a7cb53afa125472a058b2877
--- /dev/null
+++ b/agents/outliner_phase/__init__.py
@@ -0,0 +1,4 @@
+from .Deep_Semantic_Topics_Generator_1 import research_agent, research_task
+from .topic_expander_2 import structure_agent, structure_task
+from .module_organizer_3 import designer_agent, design_task
+from .review_agent_4 import review_agent, review_task
diff --git a/agents/outliner_phase/module_organizer_3.py b/agents/outliner_phase/module_organizer_3.py
new file mode 100644
index 0000000000000000000000000000000000000000..500ad38f485704654743133079292a3b5d7de9ed
--- /dev/null
+++ b/agents/outliner_phase/module_organizer_3.py
@@ -0,0 +1,49 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+from schemas import CurriculumOutline
+
+
+# ---------------------------
+# === Agent 3: Module Organizer ===
+# ---------------------------
+def designer_agent():
+ model = llm()
+ return Agent(
+ role="Module Organizer Agent (Group into 4 modules)",
+ goal=(
+ "استلم الـ20 محورًا من Agent2. نظّمهم إلى **4 وحدات**، كل وحدة تحتوي على **5 مواضيع** "
+ "مرتبة متسلسلة ومنطقية. أعطِ كل وحدة عنوانًا واضحًا ومعبّرًا (module_title بالعربية)، "
+ "وقصّر عناوين المواضيع بحيث تكون جاهزة للاستخدام في الـ Curriculum (كل موضوع عبارة "
+ "عن جملة قصيرة أو عبارة). أعد صياغة المواضيع إن لزم لتكون متجانسة معًا."
+ ),
+ backstory=(
+ "أنت كبير مصممي مناهج. مهمتك إخراج المخرجات بصيغة CurriculumOutline المتوافقة مع الـ schema."
+ ),
+ llm=model,
+ allow_delegation=False,
+ verbose=True,
+)
+
+
+def design_task(designer_agent):
+ return Task(
+ description="تنظيم المحاور العشرين إلى 4 وحدات × 5 مواضيع في كل وحدة.",
+ expected_output=(
+ "A valid JSON object with this structure:\n"
+ "{\n"
+ ' "title": "string (Arabic curriculum title)",\n'
+ ' "units": [\n'
+ " {\n"
+ ' "unit_title": "string (Arabic, must reflect the title)",\n'
+ ' "topics": ["topic1", "topic2", "topic3", "topic4", "topic5"]\n'
+ " }, ... (4 units total)\n"
+ " ]\n"
+ "}\n"
+ "The output must be valid JSON, without markdown formatting or code blocks."
+ ),
+ output_json=CurriculumOutline,
+ # output_file=os.path.join(output_dir, "curriculum_outline.json"),
+ agent=designer_agent,
+)
diff --git a/agents/outliner_phase/review_agent_4.py b/agents/outliner_phase/review_agent_4.py
new file mode 100644
index 0000000000000000000000000000000000000000..35e65aac15c0b7105f5569bd169d1f50d022b310
--- /dev/null
+++ b/agents/outliner_phase/review_agent_4.py
@@ -0,0 +1,38 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+from schemas import CurriculumOutline
+
+# ---------------------------
+# === Agent 4: Final Reviewer (اختياري) ===
+# ---------------------------
+def review_agent():
+ model = llm()
+ return Agent(
+ role="Final Review Agent",
+ goal=(
+ "راجع الناتج النهائي (4 وحدات × 5 مواضيع). صحح اللغة، احذف التكرار، وحسّن العناوين لتكون واضحة "
+ "وتتماشى مع الأسلوب التدريبي. تأكد أن 'title' يطابق الـ topic المدخل (بالعربية)."
+ ),
+ backstory=(
+ "أنت محرر تعليمي يركز على وضوح الصياغة والاتساق. لا تغيّر المحتوى الجوهري، فقط حسن الصياغة."
+ ),
+ llm=model,
+ allow_delegation=False,
+ verbose=True,
+)
+
+
+def review_task(review_agent):
+ return Task(
+ description="مراجعة نهائية لغوية وتنسيقية للـ Curriculum النهائي.",
+ expected_output=(
+ "Final polished JSON identical in structure to CurriculumOutline, "
+ "with clear Arabic titles and consistent formatting. "
+ "The output must be valid JSON, without markdown formatting or code blocks."
+ ),
+ output_json=CurriculumOutline,
+ # output_file=os.path.join(output_dir, "curriculum_outline_final.json"),
+ agent=review_agent,
+)
diff --git a/agents/outliner_phase/topic_expander_2.py b/agents/outliner_phase/topic_expander_2.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c67613e03dfdbe1fb72c19ec9ce2f63c9e3ab7b
--- /dev/null
+++ b/agents/outliner_phase/topic_expander_2.py
@@ -0,0 +1,46 @@
+from crewai import Agent, Task, Crew, Process, LLM
+import os
+import json
+from modules import llm
+from schemas import ExpandedTopicsList
+
+# ---------------------------
+# === Agent 2: Expander to 20 Topics ===
+# ---------------------------
+def structure_agent():
+ model = llm()
+ return Agent(
+ role="Expander to 20 Topics Agent (Structure & Relations)",
+ goal=(
+ "استلم قائمة المحاور المبدئية من Agent1. راجعها لإزالة التكرار ودمج المتقارب منها، "
+ "ثم أكمل ووسع القائمة لتصل إلى **بالضبط 20 محورًا** مترابطًا. "
+ "لكل محور اكتب وصفًا تفصيليًا 3-5 سطور يشرح محتوى المحور، ولماذا هو مهم، "
+ "واذكر علاقات واضحة بين المحاور (مثال: 'مرتبط بـ X لأن...'، أو 'يأتي بعد Y لأنه...'). "
+ "لا تقسم الوحدات بعد — فقط اضمن اتساق وترابط المحاور الـ20."
+ ),
+ backstory=(
+ "أنت مصمم تعليمي بارع في بناء التسلسل المنطقي بين الموضوعات. مهمتك تحويل قائمة أولية "
+ "إلى خريطة معرفية من 20 محورًا."
+ ),
+ llm=model,
+ allow_delegation=False,
+ verbose=True,
+)
+
+
+def structure_task(structure_agent):
+ return Task(
+ description="تنظيف القائمة السابقة وتوسيعها لتصل إلى 20 محورًا مترابطًا مع وصف مفصل.",
+ expected_output=(
+ "A JSON list of exactly 20 items:\n"
+ "[\n"
+ ' { "title": "string (topic title)",\n'
+ ' "description": "string (3–5 lines)",\n'
+ ' "relation": "string (e.g., related to X because...)" }\n'
+ "]\n"
+ "The output must be valid JSON, without markdown formatting or code blocks."
+ ),
+ output_json=ExpandedTopicsList,
+ # output_file=os.path.join(output_dir, "expanded_20_topics.json"),
+ agent=structure_agent,
+)
diff --git a/app.py b/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8c8d0d2d9d2147bc46bf766e4545bf77a93e671
--- /dev/null
+++ b/app.py
@@ -0,0 +1,106 @@
+import os
+import shutil
+
+# Force HOME to /tmp so CrewAI doesn't try writing to /.local
+os.environ["HOME"] = "/tmp"
+os.environ["XDG_DATA_HOME"] = "/tmp/.local/share"
+os.environ["CREWAI_STORAGE_PATH"] = "/tmp/crewai_data"
+os.environ["CREWAI_HOME"] = "/tmp/crewai_home"
+
+# Create safe directories
+os.makedirs("/tmp/.local/share", exist_ok=True)
+os.makedirs("/tmp/crewai_data", exist_ok=True)
+os.makedirs("/tmp/crewai_home", exist_ok=True)
+from crewai import Crew, Process
+import json
+from fastapi import FastAPI
+from routers import (
+ objective_route,
+ outliner_route,
+ outcome_route,
+ introduction_route,
+ source_route,
+ scraper_route,
+ final_outlines_before_content_route,
+ content_generation_route,
+ quiz_route,
+ details_before_content_route,
+)
+from routers.books import (
+ units_structure_route,
+ book_structure_route,
+ book_planning_route,
+ rag_route,
+ rag_automation_route,
+ book_content,
+ rag_admin,
+ queries_route,
+ search_route,
+ rag_sources,
+ units_intro,
+ book_enrichment,
+ reference,
+)
+
+
+app = FastAPI(title="AI Agent Project", version="1.0.0")
+
+app.include_router(outliner_route.router)
+app.include_router(objective_route.router)
+app.include_router(outcome_route.router)
+app.include_router(introduction_route.router)
+# app.include_router(source_route.router)
+# app.include_router(scraper_route.router)
+app.include_router(final_outlines_before_content_route.router)
+app.include_router(content_generation_route.router)
+app.include_router(quiz_route.router)
+app.include_router(details_before_content_route.router)
+app.include_router(units_structure_route.router)
+app.include_router(book_structure_route.router)
+app.include_router(book_planning_route.router)
+app.include_router(rag_route.router)
+app.include_router(book_content.router)
+app.include_router(rag_automation_route.router)
+app.include_router(rag_admin.router)
+app.include_router(queries_route.router)
+app.include_router(search_route.router)
+app.include_router(rag_sources.router)
+app.include_router(units_intro.router)
+app.include_router(book_enrichment.router)
+app.include_router(reference.router)
+
+# Clear Cashe
+@app.get("/reset-cache")
+def reset_cache():
+
+ paths = [
+ "/tmp/crewai_data",
+ "/tmp/crewai_home",
+ "/tmp/.local/share",
+ ]
+
+ for path in paths:
+ if os.path.exists(path):
+ shutil.rmtree(path, ignore_errors=True)
+
+ os.makedirs("/tmp/crewai_data", exist_ok=True)
+ os.makedirs("/tmp/crewai_home", exist_ok=True)
+ os.makedirs("/tmp/.local/share", exist_ok=True)
+
+ return {"message": "✅ Cache cleared successfully."}
+
+
+# Example root endpoint
+@app.get("/")
+def read_root():
+ return {"message": "Welcome to AI Agent Project API 🚀"}
+
+
+# ------------------------
+# ✅ نقطة تشغيل السيرفر
+# ------------------------
+
+# if __name__ == "__main__":
+# import uvicorn
+
+# uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
diff --git a/core/__init__.py b/core/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a235a433662472b87c76071b9382f3848d769a2
--- /dev/null
+++ b/core/__init__.py
@@ -0,0 +1,9 @@
+from .content_crew_config import safe_run_cached
+from .content_services import generate_course_content
+from .content_converter_service import convert_dict_to_html
+from .quiz_converter_service import convert_questions_dict_to_html
+from .details_before_content_converter import render_course_html
+from .books.planning_services import run_planning_on_outline
+from .books.content_services import process_book
+from .books.search_service import run_search_pipeline_parallel
+from .books.book_content_converter_service import convert_dict_to_html
diff --git a/core/books/book_content_converter_service copy.py b/core/books/book_content_converter_service copy.py
new file mode 100644
index 0000000000000000000000000000000000000000..afc609a5735f7705bd4dbb05eb003e280f08a73d
--- /dev/null
+++ b/core/books/book_content_converter_service copy.py
@@ -0,0 +1,1031 @@
+# -*- coding: utf-8 -*-
+"""
+Convert structured Arabic book JSON to a readable HTML with:
+1) المحتوى قبل المراجعة
+2) المحتوى بعد المراجعة
+3) الشكل الجديد (عرض نهائي منسّق)
+
+يدعم شكلين من البيانات:
+- الشكل القديم: chapters -> sections -> subsections
+- الشكل الحالي: chapters -> sections -> plans (dict)
+"""
+
+import argparse
+import html
+import json
+import os
+import re
+from collections import OrderedDict
+from datetime import datetime
+
+
+DEFAULT_INPUT = "/mnt/data/response_1770559830366.json"
+DEFAULT_OUTPUT = "/mnt/data/dist/index_before_after.html"
+
+
+def slugify(s: str) -> str:
+ s = (s or "").strip().lower()
+ s = re.sub(r"\s+", "-", s)
+ s = re.sub(r"[^\w\u0600-\u06FF\-]+", "", s) # Arabic + alnum + _
+ s = re.sub(r"-{2,}", "-", s).strip("-")
+ return s or "section"
+
+
+def safe_html(text: str) -> str:
+ return html.escape(text or "")
+
+
+def parse_reference_link(ref: str):
+ """
+ يرجّع:
+ - النص بدون رابط
+ - الرابط إن وُجد
+ """
+ ref = (ref or "").strip()
+ if not ref:
+ return "", ""
+
+ # الحالة الأساسية: "متاح على: "
+ m = re.search(r"متاح\s+على:\s*(https?://\S+)", ref)
+ if m:
+ url = m.group(1).rstrip(").،,؛")
+ text_before = ref[: m.start()].strip()
+ text = f"{text_before} (متاح على:)" if text_before else "متاح على:"
+ return text, url
+
+ # fallback: أي URL داخل النص
+ m2 = re.search(r"(https?://\S+)", ref)
+ if m2:
+ url = m2.group(1).rstrip(").،,؛")
+ text = ref.replace(m2.group(1), "").strip() or "مرجع"
+ return text, url
+
+ return ref, ""
+
+
+def render_ref_li(ref: str, count: int | None = None) -> str:
+ text, url = parse_reference_link(ref)
+ link_html = (
+ f' لينك'
+ if url
+ else ""
+ )
+ count_html = (
+ f" ×{count}" if count is not None else ""
+ )
+ return f"{safe_html(text)}{link_html}{count_html}"
+
+
+def render_markdownish(text: str) -> str:
+ """
+ تحويل بسيط للنص:
+ - #, ##, ###... إلى عناوين
+ - **bold** إلى strong
+ - سطور فارغة تفصل الفقرات
+ - القوائم (- / *) إلى