feat(course-plan): RAG sources + multi-modal media + assignments + student view
Some checks failed
Deploy to Staging / Deploy backend + frontend to staging (push) Failing after 14s
Some checks failed
Deploy to Staging / Deploy backend + frontend to staging (push) Failing after 14s
Builds the §24 product on top of the LangGraph runtime from §22:
Phase A (Sources / RAG)
- encoach.course.plan.source model (file | url | text)
- SourceIndexer extracts PDF (pypdf), DOCX (python-docx), HTML, plain
text and embeds chunks via the existing pgvector pipeline scoped to
plan_id, so resources.search only returns the plan's own corpus
- Endpoints: list/create/upload/reindex/delete + plan-scoped retrieval
Phase B (Deliverables)
- services.deliverables.compute_deliverables walks the plan, derives
{planned, generated, ready} per week from material + media state
- GET /api/ai/course-plan/<id>/deliverables drives the new wizard
preview step and the live progress strip on the detail page
Phase C (Multi-modal media)
- encoach.course.plan.media model + MediaService:
audio: AWS Polly (default) or ElevenLabs
image: OpenAI DALL-E 3, capped per plan via system parameter
video: local ffmpeg subprocess (image + audio -> MP4 1280x720)
- Three new agent tools (media.synthesize_audio / generate_image /
compose_video), wired into course_week_materials and a new
course_media_director agent
- Endpoints per material + week-level batch generator
Phase D (Assignments)
- encoach.course.plan.assignment supports mode='batch' (op.batch) or
mode='students' (res.users), with due_date + message + state
- REST endpoints to list / create / delete assignments
Phase E (Student view)
- /api/student/course-plans + /api/student/course-plans/<id>
enforce visibility via assignment.expand_user_ids()
- New /student/course-plans list + read-only drilldown rendering
audio/image/video tiles from /web/content/<attachment_id>
Cross-cutting
- encoach.ai.tool.category: + media (so the new tools register)
- encoach.embedding gains a plan_id filter for plan-scoped RAG
- Wizard adds Sources + Multimedia steps; AdminCoursePlanDetail
rewritten with DeliverablesStrip + SourcesCard + AssignmentsCard +
per-material MediaDrawer
- ~280 new EN + AR i18n keys (full RTL coverage)
- smoke_course_plan.py exercises every phase via odoo-bin shell;
last run: PASS A/B/D/E + DALL-E 3 image (753 KB), Polly audio
fails cleanly when AWS creds aren't configured (expected)
Documentation: §24 added to docs/PROJECT_SUMMARY.md with phase-by-phase
artefact list, endpoints, smoke test, ops notes, and gotchas.
Made-with: Cursor
This commit is contained in:
@@ -60,6 +60,7 @@ const ar: Translations = {
|
||||
dashboard: "لوحة التحكم",
|
||||
courses: "الدورات",
|
||||
myCourses: "دوراتي",
|
||||
myCoursePlans: "خططي الدراسية",
|
||||
students: "الطلاب",
|
||||
teachers: "المعلمون",
|
||||
batches: "الدفعات",
|
||||
@@ -739,8 +740,14 @@ const ar: Translations = {
|
||||
basicsDesc: "سمِّ المقرر وحدّد المستوى والمدة وعدد الساعات الأسبوعية.",
|
||||
coverage: "التغطية",
|
||||
coverageDesc: "أخبر الذكاء الاصطناعي بتوزيع الساعات على المهارات ومن هم المتعلّمون.",
|
||||
sources: "المصادر المرجعية",
|
||||
sourcesDesc:
|
||||
"ارفع ملفات PDF أو روابط أو نصوص. يستخدمها الذكاء الاصطناعي كمرجع لتوليد مواد كل أسبوع.",
|
||||
scope: "النطاق",
|
||||
scopeDesc: "اختياري: تركيز القواعد، والمصادر، وملاحظات حرّة.",
|
||||
media: "الوسائط",
|
||||
mediaDesc:
|
||||
"اختر أي وسائط يولّدها الذكاء الاصطناعي تلقائياً مع المواد النصّية.",
|
||||
review: "المراجعة",
|
||||
reviewDesc: "راجع البيانات قبل بدء التوليد.",
|
||||
},
|
||||
@@ -767,7 +774,155 @@ const ar: Translations = {
|
||||
cefrRequired: "يرجى اختيار مستوى CEFR.",
|
||||
weeksRange: "عدد الأسابيع يجب أن يكون 1 على الأقل.",
|
||||
},
|
||||
review: {
|
||||
sourcesCount_one: "{{count}} مصدر",
|
||||
sourcesCount_other: "{{count}} مصادر",
|
||||
noSources: "لا توجد مصادر",
|
||||
mediaNone: "لا يوجد توليد وسائط",
|
||||
},
|
||||
},
|
||||
sections_extras: {
|
||||
sources: "المصادر المرجعية",
|
||||
progress: "تقدّم التوليد",
|
||||
assignments: "الإسنادات",
|
||||
media: "الوسائط المُولَّدة",
|
||||
},
|
||||
sources: {
|
||||
sectionTitle: "المصادر المرجعية (RAG)",
|
||||
sectionDesc:
|
||||
"ارفع PDF أو أضف روابط أو نصوصاً. يستخدمها الذكاء الاصطناعي كمرجع عند توليد المواد الأسبوعية.",
|
||||
collected_one: "{{count}} مصدر جاهز",
|
||||
collected_other: "{{count}} مصادر جاهزة",
|
||||
empty: "لا توجد مصادر مرجعية بعد.",
|
||||
dropTitle: "أضف مواد مرجعية",
|
||||
dropHint: "PDF أو DOCX أو TXT أو HTML أو نص — حتى بضعة ميغابايت لكل ملف.",
|
||||
uploadFiles: "رفع ملفات",
|
||||
urlLabel: "إضافة رابط",
|
||||
textLabel: "أو ألصق نصاً مباشرة",
|
||||
textPlaceholder: "ألصق فقرة لتوجيه الذكاء الاصطناعي…",
|
||||
uploadFailed: "تعذّر رفع \"{{name}}\".",
|
||||
reindex: "إعادة فهرسة",
|
||||
reindexed: "أُعيدت فهرسة المصدر.",
|
||||
reindexFailed: "فشلت إعادة الفهرسة.",
|
||||
deleted: "تم حذف المصدر.",
|
||||
deleteFailed: "تعذّر حذف المصدر.",
|
||||
status: {
|
||||
pending: "في الانتظار",
|
||||
indexing: "يُفهرس…",
|
||||
indexed: "مُفهرس",
|
||||
failed: "فشل",
|
||||
},
|
||||
kindLabel: {
|
||||
file: "ملف",
|
||||
url: "رابط",
|
||||
text: "نص",
|
||||
},
|
||||
chunks_one: "{{count}} جزء",
|
||||
chunks_other: "{{count}} أجزاء",
|
||||
},
|
||||
sourceKind: {
|
||||
file: "ملف",
|
||||
url: "رابط",
|
||||
text: "نص",
|
||||
},
|
||||
deliverables: {
|
||||
title: "تقدّم التوليد",
|
||||
subtitle:
|
||||
"ما الذي سيُنتجه الذكاء الاصطناعي، وما تم إنتاجه، وما اكتمل تماماً (مواد + وسائط).",
|
||||
summary: {
|
||||
planned_one: "{{count}} مخطّط",
|
||||
planned_other: "{{count}} مخطّط",
|
||||
generated_one: "{{count}} مُولَّد",
|
||||
generated_other: "{{count}} مُولَّد",
|
||||
ready_one: "{{count}} جاهز",
|
||||
ready_other: "{{count}} جاهز",
|
||||
},
|
||||
mediaCounts: "صوت {{audio}} · صورة {{image}} · فيديو {{video}}",
|
||||
status: {
|
||||
planned: "مخطّط",
|
||||
generated: "مُولَّد",
|
||||
ready: "جاهز",
|
||||
},
|
||||
perWeek: "تفصيل لكل أسبوع",
|
||||
noWeeks: "لا توجد أسابيع — ولّد الخطة أولاً.",
|
||||
},
|
||||
media: {
|
||||
audio: "صوت",
|
||||
image: "صورة",
|
||||
video: "فيديو",
|
||||
audioTitle: "تعليق صوتي",
|
||||
audioDesc:
|
||||
"توليد صوت منطوق (Polly / ElevenLabs) لنصوص الاستماع ومحفّزات المحادثة.",
|
||||
imageTitle: "صور تغطية",
|
||||
imageDesc:
|
||||
"توليد صور DALL·E 3 لنصوص القراءة والاستماع. يحتسب من ميزانية الصور للخطة.",
|
||||
videoTitle: "فيديو شرائح",
|
||||
videoDesc: "دمج الصوت + الصورة في فيديو MP4 قصير عبر ffmpeg. أبطأ الخيارات.",
|
||||
hint:
|
||||
"الصوت مفعّل افتراضياً. الفيديو معطّل افتراضياً — فعّله بعد مراجعة الصوت والصورة.",
|
||||
drawerTitle: "وسائط \"{{title}}\"",
|
||||
drawerSubtitle: "ولّد أو احذف الصوت والصورة والفيديو.",
|
||||
generateAudio: "توليد صوت",
|
||||
generateImage: "توليد صورة",
|
||||
generateVideo: "توليد فيديو",
|
||||
generating: "جاري التوليد…",
|
||||
audioReady: "الصوت جاهز",
|
||||
imageReady: "الصورة جاهزة",
|
||||
videoReady: "الفيديو جاهز",
|
||||
audioFailed: "فشل توليد الصوت.",
|
||||
imageFailed: "فشل توليد الصورة.",
|
||||
videoFailed: "فشل توليد الفيديو.",
|
||||
deleted: "تم حذف الوسيط.",
|
||||
deleteFailed: "تعذّر حذف الوسيط.",
|
||||
open: "فتح",
|
||||
download: "تنزيل",
|
||||
noMedia: "لا توجد وسائط لهذه المادة بعد.",
|
||||
mediaForMaterial: "وسائط",
|
||||
bulk: "توليد وسائط الأسبوع",
|
||||
bulkSuccess: "اكتمل توليد وسائط الأسبوع.",
|
||||
bulkFailed: "تعذّر توليد وسائط الأسبوع.",
|
||||
provider: "المزوّد",
|
||||
},
|
||||
assignments: {
|
||||
title: "مُسندة إلى",
|
||||
empty: "لم تُسند إلى أحد بعد.",
|
||||
assign: "إسناد",
|
||||
assignTitle: "إسناد خطة المقرر",
|
||||
assignSubtitle:
|
||||
"اختر شعبة (دفعة) للجميع، أو طلاباً محدّدين. ستظهر الخطة في لوحة الطالب.",
|
||||
modeBatch: "دفعة كاملة",
|
||||
modeStudents: "طلاب محدّدون",
|
||||
pickBatch: "اختر دفعة",
|
||||
pickStudents: "اختر طلاباً",
|
||||
noBatches: "لا توجد دفعات.",
|
||||
noStudents: "لا يوجد طلاب.",
|
||||
dueDate: "تاريخ التسليم (اختياري)",
|
||||
message: "رسالة للمتعلّمين (اختياري)",
|
||||
messagePlaceholder: "ترحيب، توقّعات، مواعيد…",
|
||||
created: "تم إسناد الخطة.",
|
||||
createFailed: "تعذّر إسناد الخطة.",
|
||||
removed: "تمت إزالة الإسناد.",
|
||||
removeFailed: "تعذّر إزالة الإسناد.",
|
||||
remove: "إزالة",
|
||||
confirmRemove: "إزالة هذا الإسناد؟",
|
||||
assignedBy: "أسندها {{name}}",
|
||||
students_one: "{{count}} طالب",
|
||||
students_other: "{{count}} طلاب",
|
||||
cancel: "إلغاء",
|
||||
save: "إسناد",
|
||||
},
|
||||
student: {
|
||||
listTitle: "خططي الدراسية",
|
||||
listSubtitle:
|
||||
"خطط مناهج مخصّصة يُنشئها الذكاء الاصطناعي ويُسندها معلّمك. افتح خطة لرؤية الأسابيع والمواد والوسائط.",
|
||||
empty: "لم تُسند إليك خطط بعد.",
|
||||
open: "فتح المقرر",
|
||||
assignedBy: "أسندها {{name}}",
|
||||
due: "موعد التسليم {{date}}",
|
||||
noDue: "بدون موعد",
|
||||
backToList: "العودة إلى خططي",
|
||||
},
|
||||
wizardSourcesStep: "المصادر",
|
||||
},
|
||||
aiAdmin: {
|
||||
title: "وكلاء الذكاء الاصطناعي والأدوات",
|
||||
|
||||
Reference in New Issue
Block a user