Δημιουργία περιεχομένου μαθημάτων¶
Αυτός ο οδηγός περιγράφει βήμα προς βήμα πώς να στήσεις ένα νέο σύνολο μαθημάτων για τον Content-Loader του Adaptive Learner. Όποιος θέλει να φτιάξει ένα γλωσσικό ή θεματικό σύνολο - για δική του χρήση ή ως συνεισφορά στη δημόσια δεξαμενή περιεχομένου - καλό είναι να τον διαβάσει μία φορά ολόκληρο πριν από το πρώτο μάθημα.
Τι είναι ένα Content-Set;¶
Ένα Content-Set είναι ένα εκδοσιοποιημένο πακέτο μαθημάτων, που
ένας χρήστης μπορεί να κατεβάσει μέσω της σελίδας Set-Browser
(/content). Το plugin Content-Loader (v1.27.0) αναλαμβάνει το
discovery, τη λήψη, το caching και τη σύγκριση εκδόσεων και στους δύο
τρόπους αποθήκευσης.
Ένα σύνολο έχει τρία επίπεδα:
- Root-Manifest (
manifest.yaml) - παραθέτει κάθε σύνολο του repo. Διαβάζεται από τον Set Browser για τον κατάλογο προέλευσης. - Set-Manifest (
sets/{set-id}/manifest.yaml) - αδελφικό του Root-Manifest, παραθέτει τα αρχεία μαθημάτων του συγκεκριμένου συνόλου. - Αρχεία μαθημάτων (
sets/{set-id}/lessons/NN-slug.json) - ένα αρχείο JSON ανά μάθημα, επικυρωμένο σε κάθε λήψη έναντι του σχήματος μαθήματος (βλ. Το σχήμα είναι η μοναδική πηγή αλήθειας παρακάτω).
Τα σύνολα που αποστέλλονται με τον Adaptive Learner βρίσκονται στο
ξεχωριστό repo περιεχομένου astrapi69/adaptive-learner-content
(ελεγμένα ως αδελφικό checkout ../adaptive-learner-content και
ομαδοποιημένα offline μέσα στο build του GitHub Pages μέσω
frontend/scripts/copy-bundled-content.mjs) και είναι κατάλληλα ως
πρότυπο. Το τρέχον μέγεθος της βιβλιοθήκης (αριθμοί μαθημάτων / συνόλων
/ τομέων, ο πίνακας ανά σύνολο και οι ενεργοί τομείς) είναι το μπλοκ
CONTENT-STATS στο README.md
του έργου - αυτό το μπλοκ είναι η μοναδική πηγή αλήθειας, παραγόμενο
από ένα φρέσκο checkout περιεχομένου, οπότε αυτός ο οδηγός δεν
διπλασιάζει τους αριθμούς.
Το σχήμα είναι η μοναδική πηγή αλήθειας (EXP-039)¶
Η μορφή μαθήματος/άσκησης έχει έναν κανονικό (canonical) ορισμό:
το JSON Schema μαθήματος που αποστέλλει το npm πακέτο
learn-content-engine
(αμετάβλητο ανά δημοσιευμένο release). Μέσα σε αυτή την εφαρμογή, το
δομικό στρώμα Pydantic στο plugin Content-Loader
(adaptive_learner_content_loader.schema) αναγεννάται από αυτόν
τον καθρέφτη (scripts/generate_pydantic_models.py)· μόνο οι
σημασιολογικοί validators πολλαπλών πεδίων γράφονται στο χέρι. Το
make sync-schema ανανεώνει τον καθρέφτη και επανεκδίδει τα παράγωγα
artefacts, και πύλες byte-ισοτιμίας αποδεικνύουν ότι το
schema/*.json ισούται με το καρφιτσωμένο release του engine. Τα
σημεία που παλιότερα απέκλιναν δεν μπορούν πλέον:
schema/lesson.schema.json(+ αδελφικά αρχεία): το μηχανικά αναγνώσιμο JSON Schema (Draft 2020-12). Αναφέρσου σε αυτό από ένα.jsonμαθήματος μέσω ενός κλειδιού"$schema"κορυφαίου επιπέδου, για αυτόματη συμπλήρωση IDE και inline επικύρωση.schema/quality-rules.json: τα κοινά ελάχιστα ποιότητας (π.χ. αριθμός ασκήσεων, αριθμός αποδεκτών απαντήσεων free-text), που καταναλώνονται από τον client-side validator περιεχομένου αντί για ένα δεύτερο, χειροκίνητα συντηρούμενο αντίγραφο.- Οι τύποι μαθήματος TypeScript του frontend και η σελίδα MkDocs Lesson format reference παράγονται επίσης (μην τα επεξεργάζεσαι στο χέρι)· ακολουθούν τον καθρέφτη του engine, οπότε ξανατρέξε τη γεννήτρια μετά από κάθε re-pin.
Μια πύλη απόκλισης (make sync-schema-check, μέρος του
release-test, συν το backend/tests/test_lesson_schema_drift.py
στο make test) αποτυγχάνει αν κάποιο παραγόμενο artefact αποκλίνει
από τον καρφιτσωμένο καθρέφτη του engine. Το κλείσιμο της αλυσίδας
είναι η πύλη byte-ισοτιμίας εφαρμογής-έναντι-engine:
make engine-parity-check (scripts/check_engine_schema_parity.py),
το offline pin engine-schema-parity.test.ts και το τεστ συνοχής pin
engine-pin.test.ts (dependency του frontend/package.json ==
schema/engine-version.txt). Τα repos περιεχομένου καθρεφτίζουν το
καρφιτσωμένο release του engine (όχι αυτό το repo) και επικυρώνουν
έναντι αυτού του καθρέφτη στη δική τους CI.
Διαδικασία αλλαγής μορφής (η αυθεντία του σχήματος στο engine):
μια αλλαγή στη μορφή μαθήματος ξεκινά στο engine ή επικυρώνεται εκεί:
πρώτα PR στο engine + npm release· μετά αυτή η εφαρμογή ανεβάζει το
pin του engine (frontend/package.json + schema/engine-version.txt)
και ξανατρέχει το make sync-schema, που ανανεώνει τον καθρέφτη και
αναγεννά το δομικό στρώμα Pydantic· μόνο οι νέοι σημασιολογικοί
validators γράφονται στο χέρι· έπειτα τα repos περιεχομένου
ξανακαρφιτσώνουν το engine-version.txt τους. Μια χειροκίνητη
επεξεργασία του καθρέφτη (ή ένα μπαγιάτικο pin) κάνει κόκκινες τις
πύλες byte-ισοτιμίας· το ξεχασμένο βήμα γίνεται ορατό, ποτέ σιωπηλή
απόκλιση.
Ζεύγη γλωσσών (v1.44.0)¶
Κάθε Content-Set δηλώνει το ΖΕΥΓΟΣ γλωσσών που μεταδίδει:
target_language- αυτό που ΜΑΘΑΙΝΕΙ ο εκπαιδευόμενος (π.χ.fr).source_language- αυτό που ΜΙΛΑΕΙ ήδη ο εκπαιδευόμενος, δηλαδή η γλώσσα στην οποία είναι γραμμένα τα πεδίαbackτων καρτών, ταnotesκαι το κείμενο θεωρίας (π.χ.de).
Ακριβώς αυτό κάνει τα «Γαλλικά για Αγγλόφωνους» ένα διαφορετικό
σύνολο από τα «Γαλλικά για Γερμανόφωνους»: ίδιος στόχος (fr),
διαφορετική γλώσσα αφετηρίας (en έναντι de), διαφορετική γλώσσα
επεξήγησης. Ένας εκπαιδευόμενος βλέπει μόνο σύνολα των οποίων η
source_language ταιριάζει με μια από τις γλώσσες που μιλάει (γλώσσα
εφαρμογής συν προαιρετικές πρόσθετες γλώσσες στις Ρυθμίσεις → Μάθηση).
Τα Set-IDs κωδικοποιούν το ζεύγος ως {target}-{level}-from-{source}
(π.χ. fr-a1-from-de), και κάθε σύνολο δηλώνει ένα path, που
δείχνει στον κατάλογο γλώσσας αφετηρίας του (sets/de/fr-a1). Ένα
σύνολο φέρει επιπλέον title (στη γλώσσα αφετηρίας, αυτό που
διαβάζει ο εκπαιδευόμενος) και title_native (στη γλώσσα στόχο, ως
δευτερεύων τίτλος).
Και οι δύο κωδικοί πρέπει να είναι ISO-639-1 (δύο γράμματα), και η
source_language πρέπει να διαφέρει από την target_language. Σύνολα
πριν την v1.2 χωρίς αυτά τα πεδία φορτώνουν ακόμη: το παλιό κλειδί
language γίνεται δεκτό ως target_language, και η source_language
πέφτει πίσω στο en.
Διάταξη καταλόγων¶
Το δέντρο είναι οργανωμένο κατά ΓΛΩΣΣΑ ΑΦΕΤΗΡΙΑΣ, μετά στόχο+επίπεδο:
my-content-repo/
manifest.yaml # Root: lists every set (with path + pair)
sets/
de/ # Source language: German
fr-a1/ # Target French, level A1 -> ID fr-a1-from-de
manifest.yaml # Set: lists the lessons
lessons/
01-begruessung.json
...
assets/ # optional images / audio
en/ # Source language: English
fr-a1/ # -> ID fr-a1-from-en
...
Ευρετήριο αναζήτησης (search-index.json)¶
Η ανακάλυψη και η αναζήτηση περιεχομένου (η επιφάνεια Discover)
οδηγείται από ένα λιτό search-index.json που δημοσιεύεται στη ρίζα
του repo (~4 KB, μόνο μεταδεδομένα - κανένα περιεχόμενο καρτών). Το
επίσημο repo περιεχομένου το παρέχει, και η εφαρμογή φέρνει τα
ευρετήρια κάθε ρυθμισμένου repo από την πλευρά του client (CORS-safe,
cached στο localStorage με ένα TTL 24 ωρών stale-while-revalidate),
ώστε ένας εκπαιδευόμενος να μπορεί να ΒΡΕΙ ένα σύνολο πριν το
κατεβάσει. Κάθε καταχώρηση διαφημίζει το id, name, description
του συνόλου, τη source_language / target_language, το level,
τον domain, το lesson_count, το card_count, τα tags, ένα flag
ai_validated, ένα trust_level, ένα προαιρετικό συνοδευτικό book
και μια χρονοσφραγίδα updated_at. Κράτησέ το συγχρονισμένο με τα
manifest των συνόλων· ένα PR στο επίσημο repo το αναγεννά.
Μορφή Manifest¶
Το σχήμα πεδίων manifest (το root manifest.yaml που παραθέτει τα
σύνολα του repo, με κάθε υποχρεωτικό και προαιρετικό πεδίο) βρίσκεται
στην αναφορά του engine:
learn-content-engine, Manifest format.
Η λίστα πεδίων σκόπιμα δεν επαναλαμβάνεται εδώ: το αυστηρό σχήμα του
engine (άγνωστα πεδία απορρίπτονται) επικυρώνει κάθε manifest, και η
αναφορά του engine είναι η μοναδική έγκυρη περιγραφή της. Σύνταξε τα πεδία
του ζεύγους γλωσσών (target_language / source_language) όπως
περιγράφεται στην ενότητα «Ζεύγη γλωσσών»· το προ-v1.2 alias language
φορτώνει ακόμη, αλλά αποθαρρύνεται για νέα σύνολα.
Το προαιρετικό πεδίο visibility (engine 0.14.0+, visible
όταν λείπει) είναι μια υπόδειξη εμφάνισης για τις
εφαρμογές-καταναλωτές: το visibility: hidden ζητά από την εφαρμογή
να μην εμφανίζει το σύνολο στους εκπαιδευόμενους - προορίζεται για
fixtures αναφοράς/συμμόρφωσης, που πρέπει να μείνουν στο repo για
την επικύρωση του engine αλλά δεν είναι μαθησιακό περιεχόμενο. Η
εφαρμογή φιλτράρει τα κρυμμένα σύνολα έξω από τις επιφάνειες
περιήγησης και Discover (ακόμη κι όταν είναι ήδη στην cache)· το
engine εξακολουθεί να τα επικυρώνει. Λίστα κρυμμένων συνόλων στην
πλευρά της εφαρμογής δεν υπάρχει πλέον.
Συμπεριφορά του loader ειδική για την εφαρμογή που πρέπει να έχεις υπόψη:
- Το Set-Manifest παραθέτει κάθε αρχείο μαθήματος κάτω από
metadata.lessons, και ο Content-Loader επαναλαμβάνει αυτή τη λίστα με τη δεδομένη σειρά: τα ονόματα αρχείων στον δίσκο είναι άσχετα, μόνο η σειρά του manifest μετρά:
Σχήμα μαθήματος¶
Κάθε μάθημα είναι ένα μεμονωμένο αρχείο JSON: μεταδεδομένα κορυφαίου
επιπέδου (id, title, description, estimated_minutes), μια λίστα
από cards (τις μικρότερες μαθήσιμες μονάδες - σταθερά ids, ζεύγη
front/back, Markdown notes, tags για το SRS) και μια λίστα από
steps, κάθε ένα είτε βήμα THEORY (ένα Markdown body, προαιρετικά
ένας σύνδεσμος example_url ή inline examples) είτε βήμα EXERCISE
(ακριβώς μία άσκηση).
Η πλήρης αναφορά μορφής, πεδίο προς πεδίο - κάθε πεδίο, κάθε τύπος άσκησης, κάθε λειτουργία cloze, με παραδείγματα JSON που επικυρώνονται από τη σουίτα δοκιμών του engine - βρίσκεται στην αναφορά του engine:
- learn-content-engine -
docs/lesson-format.md - η κανονική αναφορά μορφής μαθήματος για συντάκτες και τρίτους validators (χωρίς ανάγκη checkout της εφαρμογής)
- το μηχανικά αναγνώσιμο σχήμα που ομαδοποιείται με κάθε release του
engine:
import schema from "learn-content-engine/schema/lesson.schema.json" - ο δίδυμος μέσα στην εφαρμογή: η παραγόμενη Lesson format reference
Το ομαδοποιημένο σχήμα του engine είναι byte-πανομοιότυπο με το
παραγόμενο schema/lesson.schema.json αυτού του repo (επιβάλλεται από
το make engine-parity-check), οπότε «επικυρώνεται έναντι του engine»
και «επικυρώνεται στην εφαρμογή» είναι η ίδια δήλωση.
Ποιος τύπος άσκησης για ποιον μαθησιακό στόχο¶
Διάλεξε τον τύπο άσκησης βάσει του μαθησιακού στόχου, όχι για την
ποικιλία. Η βαθμολόγηση ακριβούς αντιστοίχισης λέξη προς λέξη - ένα
word_tiles ολόκληρης πρότασης, ή ένα free_text πλήρους πρότασης -
αποτυγχάνει για την ελεύθερη παραγωγή: μια έννοια μπορεί να
διατυπωθεί με πολλούς σωστούς τρόπους, οπότε ένας ουσιαστικά σωστός
εκπαιδευόμενος βαθμολογείται λάθος λέξη προς λέξη. Αυτή είναι η πιο
αποθαρρυντική στιγμή που μπορεί να παραγάγει ένα μάθημα. Ταίριαξε αντ'
αυτού τον τύπο με τον στόχο:
| Μαθησιακός στόχος | Σωστός τύπος |
|---|---|
| Ένα γεγονός με μία απάντηση | cloze (ένα κενό) |
| Αναγνώριση μιας έννοιας | πολλαπλή επιλογή (cloze σε λειτουργία select) / matching |
| Ορισμός μιας έννοιας | cloze με κενά σε λέξεις-κλειδιά |
| Ελεύθερη εξήγηση / μεταφορά / σύγκριση | δεν υπάρχει ακόμη τύπος ακριβούς αντιστοίχισης - προς το παρόν χρησιμοποίησε cloze / πολλαπλή επιλογή· η αυτοαξιολόγηση είναι προγραμματισμένη |
| Πρόταση με μία μονοσήμαντη σειρά λέξεων (εκμάθηση γλώσσας) | word_tiles |
Εμπειρικός κανόνας: κράτησε το word_tiles για προτάσεις των οποίων η
σειρά λέξεων είναι πραγματικά μοναδική (μια άσκηση μετάφρασης), και
σύνταξε ορισμούς και γεγονότα ως cloze (ή πολλαπλή επιλογή μέσω
λειτουργίας cloze select). Ποτέ μη βάζεις έναν ελεύθερης μορφής
ορισμό σε word_tiles ή σε free_text πλήρους πρότασης - δεν υπάρχει
δίκαιη βαθμολόγηση ακριβούς αντιστοίχισης για αυτό. Πλήρης ανάλυση: βλ.
EXP-041 (docs/explorations/EXP-041-aufgabentyp-eignung-und-faire-bewertung.md).
Κατάλογος τύπων άσκησης (κατάσταση)¶
Μία αναφορά κάθε τύπου άσκησης: τι αποστέλλεται, τι είναι εκφράσιμο
χωρίς νέο τύπο, τι είναι υποψήφιο και τι αποκλείεται σκόπιμα. Το
κανονικό μοντέλο δεν επεκτείνεται εκ των προτέρων - ένας τύπος
αποστέλλεται μόνο μαζί με τον renderer του (το μητρώο
SUPPORTED_EXERCISE_TYPES πρέπει να ισούται με την enum ExerciseType·
ένα parity test το επιβάλλει, το μάθημα που πήραμε από τις περιπτώσεις
v1.4-preview / picture_choice). Νέοι τύποι προστίθενται κατόπιν
συγκεκριμένης ανάγκης περιεχομένου μέσω της συνταγής
Adding a new exercise type.
Υλοποιημένοι (η enum ExerciseType)¶
| Τύπος | Για τι (μαθησιακός στόχος, EXP-041) | Σημείωση |
|---|---|---|
matching |
Αναγνώριση / αντιστοίχιση εννοιών | Drag-pair, ≥ 3 ζεύγη. |
picture_choice |
Αναγνώριση από μια πραγματική εικόνα | ≥ 2 εικόνες, ακριβώς μία σωστή. Όχι για πολλαπλή επιλογή κειμένου. |
free_text |
Παραγωγή μιας σύντομης απάντησης τύπου γεγονότος | Ακριβής αντιστοίχιση, μετά Levenshtein ≤ 1. |
word_tiles |
Μία μονοσήμαντη σειρά λέξεων (γλώσσα) | Τα πλακίδια ανακατεύονται· accept_orderings για παραλλαγές. |
cloze (type) |
Ένα γεγονός με μία απάντηση | Ένα <input> ανά κενό. |
cloze (select) |
Μονή πολλαπλή επιλογή (όχημα legacy) | Αποδίδεται ως πατήσιμα κουμπιά (#1342). accept[0] σωστό + distractors. |
cloze (multiselect) |
«Επιλογή όλων όσων ισχύουν» (όχημα legacy) | Ακριβής αντιστοίχιση συνόλου πάνω σε accept (όλα σωστά) + distractors (#1195). |
multiple_choice |
Εγγενής πολλαπλή επιλογή κειμένου (σχήμα v1.6, #1525) | options ({text, correct?}, μοναδικά κείμενα) + multiple. Μονή = ακριβώς μία σωστή· πολλαπλή = ακριβής αντιστοίχιση συνόλου, χωρίς μερική πίστωση. |
Από το σχήμα v1.6 υπάρχει ένας εγγενής τύπος multiple_choice.
Συνυπάρχει με το όχημα cloze select/multiselect (EXP-036
§4.3, #890) - η υπάρχουσα πολλαπλή επιλογή με βάση το cloze παραμένει
έγκυρη, τίποτα δεν είναι deprecated. Προτίμησε το multiple_choice για
νέο περιεχόμενο πολλαπλής επιλογής κειμένου: η ορθότητα είναι flag ανά
επιλογή, οπότε η παγίδα της μη επικάλυψης accept/distractor δεν μπορεί
να συμβεί. Βλ. την ενότητα «Δημιουργία πολλαπλής επιλογής».
Tier επεκτάσεων (ο namespace ext:)¶
Πέρα από την κλειστή βασική enum υπάρχουν τύποι ασκήσεων στον namespace
ext:<vendor>-<name>. Είναι δομικά αδιαφανείς προς το βασικό σχήμα:
ένα μάθημα που τους χρησιμοποιεί τους δηλώνει στο requires_extensions,
και το payload επικυρώνεται από την εγγεγραμμένη επέκταση, ποτέ από το
βασικό σχήμα. Ο μηχανισμός περιγράφεται στην αναφορά του engine
learn-content-engine - docs/extensions.md.
Η εφαρμογή έχει υιοθετήσει πέντε τύπους επέκτασης
(SUPPORTED_EXT_EXERCISE_TYPES στον ExerciseDispatcher· μια πύλη
ισοτιμίας κρατά dispatcher και load guard συγχρονισμένους, ώστε
οτιδήποτε φορτώσιμο να είναι αποδόσιμο):
| Τύπος | Για τι | Payload (ext_payload) |
Υιοθέτηση |
|---|---|---|---|
ext:al-categorization |
Ταξινόμηση όρων σε ομάδες | categories: [{name, items[]}], τουλάχιστον 2 ομάδες |
#1591 (πρώτος τύπος επέκτασης, καταγραφή #1579) |
ext:al-error-correction |
Διόρθωση ενός εσφαλμένου κειμένου | tokens[] + error_index + accept[] |
#1593 |
ext:al-reading-comprehension |
Κατανόηση κειμένου (απόσπασμα + ερωτήσεις) | passage + questions[] (κάθε μία υποερώτηση multiple_choice / free_text) |
#1603 |
ext:al-graded-quiz |
Βαθμολογημένο κουίζ | questions[] (κάθε μία με points) + προαιρετικό pass_threshold |
#1616· το σύνολο αναφοράς demo είναι κρυμμένο από το Discover / Τα μαθήματά μου (#1702) |
ext:al-dictation |
Ηχητική υπαγόρευση (άκου, μετά μετάγραψε) | audio (ένα κλιπ assets/ ή ένα data URI ενσωματωμένο μέσω του upload του επεξεργαστή, #1911) + accept[] (ανεκτική αντιστοίχιση μεταγραφής) |
#1881 (πέμπτη υιοθέτηση) |
Δύο διαδρομές δημιουργίας. Οι ασκήσεις επέκτασης μπορούν να
δημιουργηθούν (α) απευθείας ως JSON στο repo περιεχομένου (η κανονική
διαδρομή, που περιγράφεται στην αναφορά του engine), ή (β) μέσα στην
εφαρμογή. Ο Lesson Creator απέκτησε έναν οδηγό δημιουργίας
επεκτάσεων (#1852), προσβάσιμο από το πρότυπο Advanced exercise
types στο βήμα 1, που καλύπτει και τους πέντε τύπους (#1859
categorization + error-correction, #1865 reading-comprehension +
graded-quiz, #1887 dictation). Η υπαγόρευση είναι επίσης προσβάσιμη από
τον βασικό επιλογέα τύπων άσκησης στο βήμα 3, πίσω από μια γενικευμένη
πύλη requires_extensions (#1895). Και οι δύο διαδρομές παράγουν το ίδιο
JSON μαθήματος και ορίζουν το requires_extensions (με έκδοση, π.χ.
ext:al-dictation@1).
Παράδειγμα ανά τύπο επέκτασης¶
Κάθε μπλοκ είναι το αντικείμενο άσκησης όπως εμφανίζεται σε ένα .json
μαθήματος· τα δεδομένα ανά τύπο βρίσκονται κάτω από το ext_payload. Η
κανονική αναφορά πεδίων είναι το docs/extensions.md του engine.
{
"type": "ext:al-categorization",
"prompt": "Sort each word into fruit or vegetable.",
"ext_payload": {
"categories": [
{"name": "Fruit", "items": ["apple", "banana"]},
{"name": "Vegetable", "items": ["carrot", "potato"]}
]
}
}
{
"type": "ext:al-error-correction",
"prompt": "One word is wrong. Correct it.",
"ext_payload": {
"tokens": ["The", "two", "child", "are", "playing"],
"error_index": 2,
"accept": ["children"]
}
}
{
"type": "ext:al-reading-comprehension",
"prompt": "Read the text and answer.",
"ext_payload": {
"passage": "Marie is sitting in a café. She orders a coffee and reads a book.",
"questions": [
{
"prompt": "Where is Marie?",
"type": "multiple_choice",
"options": [
{"text": "In a café", "correct": true},
{"text": "At home"},
{"text": "At the station"}
]
}
]
}
}
{
"type": "ext:al-graded-quiz",
"prompt": "Greetings quiz.",
"ext_payload": {
"pass_threshold": 60,
"questions": [
{
"prompt": "How do you say 'hello' in French?",
"type": "multiple_choice",
"points": 1,
"options": [
{"text": "Bonjour", "correct": true},
{"text": "Merci"},
{"text": "Au revoir"}
]
}
]
}
}
{
"type": "ext:al-dictation",
"prompt": "Listen and type what you hear.",
"ext_payload": {
"audio": "assets/audio/comment-ca-va.mp3",
"accept": ["Comment ça va ?", "Comment ca va"]
}
}
Διαθεσιμότητα στον οδηγό μαθήματος¶
Το παίξιμο (υπάρχει renderer), το δημιουργήσιμο (το μείγμα AI μπορεί να
το παραγάγει) και η χειροκίνητη προσθήκη (προσθέτεις και επεξεργάζεσαι
μία με το χέρι στο βήμα 3) είναι τρία διαφορετικά πράγματα. Και οι έξι
βασικοί τύποι είναι παίξιμοι ΚΑΙ δημιουργήσιμοι: ο επιλογέας τύπων στον
οδηγό δημιουργίας μαθήματος (ALL_TYPES στο ExerciseGenerator.tsx)
προσφέρει κάθε βασικό τύπο, και κάθε άσκηση του βήματος 3 είναι
επεξεργάσιμη inline και αναδιατάξιμη, με ένα χειροκίνητο κουμπί
+ Προσθήκη άσκησης (#1849, #1853).
| Τύπος | Παίξιμο | Δημιουργήσιμο (μείγμα AI) | Χειροκίνητη προσθήκη (βήμα 3) |
|---|---|---|---|
matching |
ναι | ναι | ναι |
free_text |
ναι | ναι | ναι |
cloze |
ναι | ναι | ναι |
word_tiles |
ναι | ναι | ναι |
picture_choice |
ναι | ναι | ναι |
multiple_choice |
ναι | ναι (#1853· έλεγχος λειτουργίας μονής/πολλαπλής #1888) | ναι |
ext:al-dictation |
ναι | όχι | ναι, μέσω του βασικού επιλογέα (#1895) ή του οδηγού επεκτάσεων (#1887) |
ext:al-categorization |
ναι | όχι | μέσω του οδηγού επεκτάσεων (#1859) |
ext:al-error-correction |
ναι | όχι | μέσω του οδηγού επεκτάσεων (#1859) |
ext:al-reading-comprehension |
ναι | όχι | μέσω του οδηγού επεκτάσεων (#1865) |
ext:al-graded-quiz |
ναι | όχι | μέσω του οδηγού επεκτάσεων (#1865) |
Οι τέσσερις τύποι επέκτασης πλην της υπαγόρευσης δημιουργούνται στον οδηγό επεκτάσεων (ή ως JSON στο repo περιεχομένου), ποτέ αναμεμειγμένοι στη βασική δημιουργία AI.
Το listen-first είναι λειτουργία, όχι τύπος. Από το #1687 (απόφαση
1600, επιλογή A) οι ασκήσεις free_text και matching μπορούν να¶
φέρουν ένα στοιχείο audio-first (άκου πρώτα, μετά απάντησε). Ο τύπος της
άσκησης δεν αλλάζει. Η επιλογή B της ίδιας απόφασης, ένας τύπος
υπαγόρευσης, κυκλοφόρησε ως η επέκταση ext:al-dictation (#1881),
τεκμηριωμένη στο tier επεκτάσεων παραπάνω.
Ο Lesson Creator ως εργαλείο δημιουργίας¶
Ο Lesson Creator μέσα στην εφαρμογή (/create-lesson) είναι μια πλήρης
επιφάνεια δημιουργίας, όχι μόνο ένα κουμπί δημιουργίας-με-AI:
- Κάθε άσκηση του βήματος 3 είναι επεξεργάσιμη επιτόπου. Κάθε παραγόμενη ή προστεθειμένη άσκηση ανοίγει σε έναν inline επεξεργαστή (και οι έξι βασικοί τύποι, συν οι επεξεργαστές επεκτάσεων)· αναδιάταξη με σύρσιμο, διαγραφή, ή αναδημιουργία όλου του μείγματος (#1845).
- Πρόσθεσε μια άσκηση με το χέρι. Το κουμπί + Προσθήκη άσκησης διαλέγει έναν τύπο και προσαρτά μια κενή άσκηση κατευθείαν στον inline επεξεργαστή, ώστε να μπορείς να συντάσσεις χωρίς καμία δημιουργία AI (#1849, #1853). Ο επιλογέας παραθέτει τους έξι βασικούς τύπους συν την υπαγόρευση (#1895).
- Η παραδειγματική πρόταση οδηγεί τη δημιουργία. Μια κάρτα (βήμα 2)
μπορεί να φέρει μια προαιρετική παραδειγματική πρόταση. Αυτή είναι
που ενεργοποιεί τη δημιουργία
clozeκαιword_tilesγια εκείνη την κάρτα (για το cloze, η πρόταση πρέπει να περιέχει τον όρο front της κάρτας ώστε να μπορεί να αφαιρεθεί ως κενό), και μια εικόνα κάρτας ενεργοποιεί τοpicture_choice. Χωρίς αυτά, οι τύποι εκείνοι παραλείπονται σιωπηλά, και το βήμα 3 εξηγεί ποιος επιλεγμένος τύπος δεν παρήγαγε τίποτα (#1847, #1848). - Τα παραγόμενα prompts ακολουθούν τη γλώσσα του UI. Τα πρότυπα οδηγιών ασκήσεων τοπικοποιούνται κατά τη δημιουργία (#1857), ώστε ένας συντάκτης σε γερμανικό UI να παίρνει γερμανικά prompts, όχι αγγλικές προεπιλογές. Όταν ανοίγεις ένα παλαιότερο μάθημα για επεξεργασία, κάθε prompt άσκησης που είναι ακόμη byte-πανομοιότυπο με μια legacy αγγλική προεπιλογή μεταναστεύει ευκαιριακά στο πρότυπο της γλώσσας UI (μόνο σε κατάσταση επεξεργασίας, διατηρείται μόνο αν αποθηκεύσεις) (#1861).
Εκφράσιμο χωρίς νέο τύπο (συμβάσεις, όχι τύποι)¶
| Έννοια | Πώς |
|---|---|
| Σωστό/Λάθος, Ναι/Όχι | multiple_choice δύο επιλογών (ή cloze select δύο επιλογών) |
| Dropdown / radio / checkbox | Παρουσίαση του multiple_choice / cloze select - όχι ξεχωριστοί τύποι |
Προγραμματισμένο αν χρειαστεί (υποψήφιοι - ΟΧΙ δέσμευση)¶
| Υποψήφιος | Κοντά σε | Πότε |
|---|---|---|
| Διάταξη / ταξινόμηση | word_tiles |
Μόνο κατόπιν συγκεκριμένης ανάγκης περιεχομένου, τότε μέσω της συνταγής. |
| Πεδίο αριθμού (αριθμητική σύγκριση) | free_text |
Μόνο κατόπιν συγκεκριμένης ανάγκης περιεχομένου, τότε μέσω της συνταγής. |
Σκόπιμα αποκλεισμένο¶
| Αποκλεισμένο | Γιατί (μία γραμμή) |
|---|---|
| Έκθεση / μεγάλο κείμενο / σχέδιο / τύπος / αξιολόγηση από ομοτίμους / ελεύθερη αυτοαξιολόγηση | Δεν βαθμολογείται δυαδικά από το SRS· η αυτοαξιολόγηση αναβλήθηκε (#1268). |
| Ήχος / βίντεο / μεταφόρτωση αρχείου | Αποθήκευση + υποδομή· συγκρούεται με το offline-first. Μοναδική εξαίρεση: σύντομα ηχητικά κλιπ υπαγόρευσης, που ο επεξεργαστής ασκήσεων ενσωματώνει στο μάθημα ως data URI. |
| Hotspot / προσομοίωση / μνήμη / σταυρόλεξο | Κόπος υλοποίησης χωρίς αξία SRS (μεταγενέστερη, ξεχωριστή απόφαση αν ποτέ). |
| Πίνακας / Likert / ολισθητής | Τύποι έρευνας, όχι τύποι μάθησης. |
| Επιλογείς ημερομηνίας / ώρας | Τύποι φόρμας, όχι τύποι μάθησης. |
Αναφορά τύπων ασκήσεων¶
Η αναφορά πεδίων ανά τύπο - matching, picture_choice, free_text,
word_tiles, multiple_choice και cloze με τις λειτουργίες του
type / select / multiselect: υποχρεωτικά πεδία, παραδείγματα JSON
και οι σημασιολογικοί κανόνες (δείκτες cloze ___ == blanks,
αναφορική ακεραιότητα card_ids, μη επικάλυψη accept/distractor στο
multiselect, ακριβώς-μία-σωστή στο picture-choice) - βρίσκεται στην
αναφορά του engine:
learn-content-engine - docs/lesson-format.md.
Κάθε παράδειγμα JSON εκεί εξάγεται και επικυρώνεται από τη σουίτα
δοκιμών του engine, οπότε η αναφορά δεν μπορεί να σαπίσει. Οι συμβάσεις
δημιουργίας ειδικές για την εφαρμογή παρακάτω παραμένουν εδώ.
Δημιουργία πολλαπλής επιλογής¶
Προτιμώμενο (σχήμα v1.6+, #1525): ο εγγενής τύπος
multiple_choice. Κάθε επιλογή φέρει το δικό της flag correct,
οπότε δεν υπάρχουν ξεχωριστές λίστες accept/distractors που πρέπει να
μένουν ξένες μεταξύ τους. Το multiple: false (προεπιλογή) είναι
μονή επιλογή (ακριβώς μία σωστή)· το multiple: true είναι «επιλογή
όλων όσων ισχύουν» (βαθμολόγηση ακριβούς συνόλου, χωρίς μερική
πίστωση):
{
"id": "ex-capital",
"type": "multiple_choice",
"prompt": "What is the capital of France?",
"card_ids": ["card-paris"],
"options": [
{"text": "Paris", "correct": true},
{"text": "Berlin"},
{"text": "Madrid"},
{"text": "Rome"}
]
}
Όχημα legacy (παραμένει πλήρως έγκυρο: συνύπαρξη, τίποτα
deprecated): πριν από την v1.6, η πολλαπλή επιλογή κειμένου
δημιουργούνταν ως cloze σε λειτουργία select (EXP-036 §4.3,
890). Μια ερώτηση μονής απάντησης είναι ένα cloze με ένα κενό: η¶
sentence (που τελειώνει σε ___) είναι η ερώτηση, το accept[0]
του κενού είναι η σωστή επιλογή και τα distractors είναι οι
λανθασμένες. Παράδειγμα:
"sentence": "The capital of France is ___.",
"blanks": [{"accept": ["Paris"]}], "cloze_mode": "select",
"distractors": ["Berlin", "Madrid", "Rome"].
Μπορείς επίσης να βάλεις όλη την ερώτηση στο prompt και να
χρησιμοποιήσεις ένα σκέτο "sentence": "___"· ο renderer δείχνει ένα
<select> από τη σωστή απάντηση + τους distractors, βαθμολογεί την
επιλογή, δίνει feedback και τροφοδοτεί το SRS:
{
"id": "ex-hook-state",
"type": "cloze",
"prompt": "Which hook manages local state in a function component?",
"card_ids": ["card-usestate"],
"sentence": "___",
"blanks": [{"accept": ["useState"]}],
"cloze_mode": "select",
"distractors": ["useEffect", "useContext", "useRef"]
}
Μη δημιουργείς ποτέ πολλαπλή επιλογή κειμένου ως
picture_choice. Αυτός ο τύπος είναι μόνο για πραγματικά assets εικόνων· για επιλογές κειμένου αποδίδει πλακίδια placeholder, όχι ένα χρηστικό στοιχείο ελέγχου (πρβλ. astrapi69/adaptive-learner-content-test#10). Η πολλαπλή επιλογή κειμένου είναιmultiple_choice(προτιμώμενο) ήclozeσε λειτουργίαselect, όπως παραπάνω.
Η «επιλογή όλων όσων ισχύουν» (δύο ή περισσότερες σωστές
απαντήσεις, π.χ. μια ερώτηση εξέτασης διπλώματος οδήγησης)
χρησιμοποιεί cloze_mode: "multiselect":
{
"type": "cloze",
"cloze_mode": "multiselect",
"sentence": "Which cities are in Germany?",
"accept": ["Berlin", "Hamburg"],
"distractors": ["Vienna", "Zurich"]
}
Πολλαπλά κενά ανά cloze υποστηρίζονται: κάθε ___ στην πρόταση
αντιστοιχίζεται με τη σειρά στην επόμενη καταχώρηση στο blanks. Κάθε
κενό μπορεί να έχει δικό του hint + placeholder + λίστα accept. Το SRS
στοιχείων ξεδιπλώνει ανά κενό ένα ElementAttempt - όποιος συμπληρώνει
άπταιστα το κενό A, αλλά αστοχεί συνεχώς στο κενό B, λαμβάνει
παρακολούθηση κατάκτησης με κενο-γκρανουλάρ ανάλυση.
Ρόλοι token σε Cards (Φάση 52I / v1.35.0) - προαιρετικά μεταδεδομένα Card, με τα οποία η γεννήτρια cloze μπορεί στον χρόνο εκτέλεσης (συνεδρίες review + ο γύρος διόρθωσης στο τέλος του μαθήματος) να επιλέξει ένα σημασιολογικά σημαντικό κενό:
{
"id": "art-un",
"front": "un chat",
"back": "eine Katze",
"tags": ["article"],
"token_roles": [
{"token": "un", "role": "article"}
]
}
Κλειστή enum ρόλων: article / verb / noun / adjective /
preposition / gender_marker / tense_marker. Η προσθήκη ενός
ρόλου είναι μια αναβάθμιση δευτερεύουσας έκδοσης σχήματος - μην την
επεκτείνεις inline.
Μη λατινικές γραφές: σύμβαση μεταγραφής¶
Δεσμευτικοί κανόνες για σύνολα των οποίων η γλώσσα στόχος χρησιμοποιεί μη λατινική γραφή (ιαπωνικά, κινέζικα, κορεατικά, ελληνικά, χίντι, ...). Καθιερωμένοι και εφαρμοσμένοι στο repo περιεχομένου - προηγούμενα: content#90, content#91· σαρώσεις υπόλοιπων κενών: content#106, content#107.
1. Κανόνας κατεύθυνσης. Η μεταγραφή είναι μόνο για τη μη λατινική γλώσσα στόχο όταν η γλώσσα αφετηρίας γράφεται σε λατινική γραφή (de→ja, de→zh, de→ko, ...). Μια μη λατινική γλώσσα αφετηρίας με λατινόγραφη γλώσσα στόχο (hi→en, el→fr) δεν παίρνει μεταγραφή - ο εκπαιδευόμενος διαβάζει ήδη τη δική του γραφή.
2. Μορφή. Στρογγυλές παρενθέσεις αμέσως μετά το πρωτότυπο: こんにちは (konnichiwa). Στα βήματα θεωρίας πάντα· στις επιλογές και τα prompts μόνο όπου είναι αβλαβές (βλ. τον κανόνα μη προδοσίας).
3. Κανόνας μη προδοσίας (ο πυρήνας). Η μεταγραφή δεν πρέπει ποτέ
να αποκαλύπτει τη λύση. Οι εργασίες ανάγνωσης γραφής, η αναγνώριση
τόνου, τα πλακίδια word_tiles και τα συμφραζόμενα προτάσεων cloze
παραμένουν ΧΩΡΙΣ μεταγραφή στο ζητούμενο στοιχείο· οι εργασίες σημασίας
την παίρνουν. Όταν υπάρχει αμφιβολία, άφησέ την έξω.
- Θετικό παράδειγμα (αντιστοίχιση σημασίας, content#91): το ζεύγος
matching
{"left": "妈 (mā)", "right": "Mama / Mutter"}- η ζητούμενη γνώση είναι η σημασία, οπότε το βοήθημα ανάγνωσης δεν προδίδει τίποτα. - Αρνητικό παράδειγμα (ανάγνωση γραφής, content#91): οι ασκήσεις
ανάγνωσης γραφής
ko-a1/01-hangul-lesenπαραμένουν χωρίς μεταγραφή, επειδή η ρωμανοποίηση ΕΙΝΑΙ η απάντηση (χαρακτήρας → ήχος)·가 (ga)στο prompt θα έδινε στον εκπαιδευόμενο τη λύση.
4. Πρότυπη ρωμανοποίηση ανά γλώσσα, συνεπής μέσα σε ένα σύνολο: ιαπωνικά Hepburn, κινέζικα Pinyin ΜΕ σημάδια τόνου, κορεατικά Revised Romanization, ελληνικά/χίντι μια κοινή απλοποιημένη μεταγραφή. Ποτέ μην αναμειγνύεις συστήματα μέσα σε ένα σύνολο.
5. Εργασίες πληκτρολόγησης (free_text / cloze σε λειτουργία
type): το accept[0] είναι η κανονική ρωμανοποιημένη μορφή· επιπλέον
δέξου κοινές παραλλαγές - ιαπωνικά: γραφές Kunrei (si/ti/tu/hu/zi, π.χ.
konnitiwa δίπλα στο konnichiwa)· κινέζικα: Pinyin χωρίς τόνους
(nihao δίπλα στο nǐ hǎo)· κορεατικά: διαδεδομένες εναλλακτικές
(π.χ. annyeong haseyo). Μνημονικό: μια άσκηση δεν πρέπει ποτέ να
αποτυγχάνει στο πληκτρολόγιο του εκπαιδευόμενου. Προηγούμενο
(μπλοκάρισμα IME, content#107): ένα cloze που δεχόταν μόνο το 가 ήταν
άλυτο χωρίς κορεατικό IME - το ρωμανοποιημένο ga έπρεπε να γίνει
επίσης δεκτό.
Ποιος τύπος φέρει ποιον μαθησιακό στόχο: βλ. την ενότητα «Κατάλογος τύπων άσκησης (κατάσταση)».
Κατεύθυνση άσκησης (v1.46.0 / EXP-018)¶
Κάθε άσκηση δέχεται ένα προαιρετικό πεδίο direction, που δηλώνει προς
ποια κατεύθυνση εξασκούν οι εκπαιδευόμενοι την κάρτα:
target_to_source(προεπιλογή) - ΑΝΤΙΛΗΠΤΙΚΑ: εμφανίζεται η γλώσσα στόχος, αναγνωρίζεται η γλώσσα αφετηρίας (ευκολότερο).source_to_target- ΠΑΡΑΓΩΓΙΚΑ: εμφανίζεται η γλώσσα αφετηρίας, παράγεται η γλώσσα στόχος (δυσκολότερο).both/random- αφήνει στον renderer / στην προσαρμοστική γεννήτρια την επιλογή μιας συγκεκριμένης κατεύθυνσης ανά προσπάθεια.
{
"type": "matching",
"direction": "source_to_target",
"card_ids": ["bonjour"],
"pairs": [{ "left": "Bonjour", "right": "Guten Tag" }]
}
Το πεδίο είναι additive - το σχήμα παραμένει στην έκδοση 1.2, και
μαθήματα χωρίς direction συμπεριφέρονται ακριβώς όπως πριν
(αντιληπτικά). Το SRS παρακολουθεί την κατάκτηση ανά κατεύθυνση: μια
αντιληπτικά κατακτημένη κάρτα δεν είναι ακόμη παραγωγικά κατακτημένη.
Οι ασκήσεις cloze είναι συμφραζομενικά δεσμευμένες και αγνοούν το
direction. Για μια προοδευτική δυσκολία κρατάς τα πρώιμα μαθήματα
αντιληπτικά και εισάγεις το source_to_target σε μεταγενέστερα μαθήματα
(ακριβώς αυτό κάνει το ενσωματωμένο pilot-περιεχόμενο).
Σχολιασμοί για την προσαρμοστική γεννήτρια μαθημάτων (v1.36.0+)¶
Η προσαρμοστική γεννήτρια μαθημάτων από τη Φάση 53
(/adaptive-lesson/:setId, F-114) συνδυάζει εκ νέου τις υπάρχουσες
ασκήσεις, ώστε να αντιμετωπίσει στοχευμένα τις συγκεκριμένες αδυναμίες
των εκπαιδευομένων. Η γεννήτρια λειτουργεί χωρίς πρόσθετους σχολιασμούς,
δύο πεδία όμως την κάνουν σημαντικά εξυπνότερη:
- Ευρύτερη κάλυψη
token_rolesσε κάρτες. Η γεννήτρια χρησιμοποιεί ταtoken_rolesγια να: - Επιλέγει σημασιολογικά λογικά κενά, όταν δημιουργούνται παραλλαγές cloze από σφάλματα (ήδη στην v1.35.0)
- Ταξινομεί σφάλματα ως
article_gender/verb_conjugation, για τα chips «εστίαση άσκησης» στο Dashboard (53E) - Βρίσκει ΕΝΑΛΛΑΚΤΙΚΕΣ ασκήσεις, που ελέγχουν το ίδιο στοιχείο, όταν
η αρχική άσκηση ήταν λάθος (53D λογική παραλλαγών - βρίσκει
υποψήφιους, των οποίων η κάρτα έχει μια κατάλληλη καταχώρηση
token_roles)
Πρόσθεσε σε ΚΑΘΕ κάρτα που διδάσκει μια δική της γραμματική μονάδα
(άρθρα, κλιμένες μορφές ρημάτων, ουσιαστικά με γένος) μια καταχώρηση
token_roles. Κόστος: μια πρόσθετη καταχώρηση JSON ανά κάρτα·
όφελος: σημαντικά πλουσιότερη προσαρμοστική δημιουργία.
- Tags καρτών όπως
tags: ["article", "masculine"]διαβάζονται από τον ταξινομητή σφαλμάτων ως fallback, όταν λείπουν ταtoken_roles. Δεν αντικαθιστούν ταtoken_roles- είναι ένας φθηνός μεσοβέζικος σχολιασμός.
Τι δεν χρειαζόμαστε ΑΚΟΜΗ (μετατεθειμένο σε μελλοντική αναβάθμιση σχήματος):
- Διασταυρούμενες αναφορές
related_cardsανάμεσα σε κάρτες από διαφορετικά μαθήματα - Αξιολογήσεις δυσκολίας ανά άσκηση (η γεννήτρια εκτιμά τη δυσκολία
προς το παρόν από το
exercise.type) - Παραδειγματικές προτάσεις ανά κάρτα στο
notes, αναλύσιμες ως εναλλακτικά συμφραζόμενα cloze (η γεννήτρια cloze χρησιμοποιεί αποκλειστικά τοfront)
Εμπειρικός κανόνας: πρόσθεσε token_roles σε κάθε κάρτα που διδάσκει
ένα γραμματικό token. Αυτή είναι μακράν η πιο αποτελεσματική συνήθεια
συντάκτη για το προσαρμοστικό σύστημα.
Assets (εικόνες που φέρνει ένα σύνολο) - v1.37.0+¶
Οι ασκήσεις Picture-Choice και οι εικόνες εξωφύλλου καρτών προέρχονται από δύο πηγές: 1. Αρχεία asset συντάκτη, δηλωμένα στο Set-Manifest και αποστελλόμενα δίπλα στο JSON μαθήματος 2. Placeholder-SVGs, παραγόμενα από το Runtime, όταν δεν υπάρχει asset (χρωματικοί πίνακες για λέξεις χρωμάτων, μεγάλα ψηφία για αριθμούς, στυλ avatar για οτιδήποτε άλλο)
Αν δημοσιεύσεις ένα σύνολο χωρίς assets, το Picture-Choice λειτουργεί παρ' όλα αυτά - η γεννήτρια Placeholder-SVG καλύπτει χρώματα + αριθμούς αυτόματα και πέφτει πίσω για οτιδήποτε άλλο σε έναν ντετερμινιστικό avatar.
Διάταξη καταλόγων¶
Μέσα στον κατάλογο του συνόλου, τα assets βρίσκονται κάτω από assets/:
sets/
language-fr-a1/
manifest.yaml
lessons/
01-greetings.json
02-numbers.json
...
assets/
img/
chat.png
chien.png
oiseau.png
Δήλωση Manifest¶
Κάθε asset πρέπει να δηλωθεί στο Set-Manifest, ώστε ο downloader να ξέρει τι να φέρει:
sets:
- id: language-fr-a1
title: French A1
language: fr
level: A1
version: '1.0.0'
lesson_count: 10
assets:
- path: img/chat.png
size_kb: 45
- path: img/chien.png
size_kb: 38
Το path είναι σχετικό προς τον κατάλογο assets/ του συνόλου (ΟΧΙ
προς το JSON μαθήματος). Στο JSON μαθήματος οι ασκήσεις Picture-Choice
αναφέρουν assets ΜΕ το πρόθεμα assets/:
{
"type": "picture_choice",
"prompt": "Welches ist 'chat'?",
"images": [
{"src": "assets/img/chat.png", "label": "Katze", "is_correct": "true"},
{"src": "assets/img/chien.png", "label": "Hund"}
]
}
Το frontend αφαιρεί το πρόθεμα assets/ αυτόματα κατά την κλήση του
asset-resolver, ώστε το JSON μαθήματος να παραμένει στη διαισθητική για
τους συντάκτες μορφή.
Όρια μεγέθους + μορφής¶
- Όριο ανά asset: 500 KiB. Ο επικυρωτής manifest απορρίπτει assets
των οποίων το δηλωμένο
size_kbυπερβαίνει αυτό το όριο. Ο downloader απορρίπτει επίσης assets των οποίων το πραγματικό μέγεθος bytes υπερβαίνει τη δήλωση κατά περισσότερο από 10% - κρατά το manifest ειλικρινές. - Soft-Limit ανά σύνολο: 10 MiB συνολικό μέγεθος. Ο επικυρωτής προειδοποιεί, αλλά δεν απορρίπτει.
- Αποδεκτές μορφές:
.png/.jpg/.jpeg/.webp/.svg. Κανένα GIF (το κινούμενο περιεχόμενο αποσπά την προσοχή), κανένα BMP (καμία συμπίεση). Για φωτογραφίες προτίμησε WebP - σημαντικά μικρότερο από PNG με συγκρίσιμη ποιότητα. Για εικονίδια + διαγράμματα προτίμησε SVG - κλιμακώνεται καθαρά + ελάχιστο μέγεθος αρχείου.
Συστάσεις μεγέθους¶
Τα πλακίδια Picture-Choice αποδίδονται έως το πολύ 150x150 px στον
desktop και 100x100 px στο κινητό (object-fit: contain). Πηγαίες
εικόνες με 300x300 px δίνουν στις οθόνες Retina το καλύτερο αποτέλεσμα
χωρίς περιττή απαίτηση δεδομένων. PNGs πάνω από 150 KiB σπάνια δείχνουν
καλύτερα από ένα καλά συμπιεσμένο WebP μισού μεγέθους.
Πότε αρκεί το Runtime-Placeholder¶
Τρία είδη μαθημάτων, όπου το Runtime-Placeholder είναι τόσο καλό, που οι εικόνες συντάκτη δεν φέρνουν μαθησιακό όφελος:
- Μαθήματα χρωμάτων (
rouge/rojo/rot/red): η γεννήτρια placeholder δημιουργεί ένα χρωματιστό πλακίδιο hex που ταιριάζει στο όνομα του χρώματος. Τα πλακίδια συντάκτη είναι περιττά. - Μαθήματα αριθμών (
7/42/1492): το placeholder αποδίδει τα ψηφία μεγάλα + κεντραρισμένα. Οι εικόνες συντάκτη θα είχαν νόημα μόνο σε μη αραβικά αριθμητικά συστήματα. - Αφηρημένες έννοιες χωρίς προφανή οπτική αναπαράσταση (
patience,liberté): το placeholder avatar παρέχει μια σαφή οπτική άγκυρα, χωρίς να επιβάλλει μια αμφιλεγόμενη επιλογή εικονιδίου.
Για οτιδήποτε άλλο (ζώα, αντικείμενα, φαγητό, τόπους, μέλη του σώματος) οι εικόνες συντάκτη βοηθούν μετρήσιμα στην αναγνώριση + ανάκληση.
Λίστα ελέγχου ποιότητας¶
Πριν το PR για ένα νέο μάθημα έλεγξε:
- [ ] 3-5 βήματα θεωρίας + 8-12 ασκήσεις ανά μάθημα
- [ ] Τουλάχιστον 3 τύποι ασκήσεων εκπροσωπούνται (matching, picture-choice, free-text, word-tiles ή cloze - cloze από v1.35.0)
- [ ] Βήματα θεωρίας ≤ 200 λέξεις ανά βήμα
- [ ] Ασκήσεις Free-Text: ≥ 3 παραλλαγές accept + ≥ 3 distractors
- [ ] Word-Tiles: ≥ 3 πλακίδια ανά άσκηση
- [ ] estimated_minutes: 10-15 (ρεαλιστικά, όχι εξιδανικευμένα)
- [ ] Οι distractors είναι λάθος-αλλά-εύλογοι - σημασιολογικά συγγενείς, ποτέ τυχαίοι
- [ ] Card-Notes προσφέρουν πραγματική προστιθέμενη αξία (προφορά, ψευδόφιλοι, σημαία εξαίρεσης)
- [ ] Προοδευτική δομή: μεταγενέστερες έννοιες χτίζουν πάνω σε προηγούμενες στο ίδιο σύνολο
- [ ] Πολιτισμική ακρίβεια: πραγματική χρήση γλώσσας, όχι μόνο σχολικές φράσεις
- [ ] Επικύρωση σχήματος: το μάθημα φορτώνει καθαρά μέσω
dict_to_lesson()(δες Τοπικός έλεγχος) - [ ] Ακεραιότητα Card-ID: κάθε
exercise.card_ids[i]υπάρχει στοcards[]του μαθήματος - [ ] Ζεύγος γλωσσών:
target_language+source_languageορισμένα (ISO 639-1, διαφορετικά),title_nativeπαρόν
Επικύρωση (δύο επίπεδα, v1.44.0)¶
Το περιεχόμενο διασφαλίζεται μέσω δύο επιπέδων επικύρωσης με τους ΙΔΙΟΥΣ ελέγχους:
- Στην εφαρμογή, πριν την κοινοποίηση. Κατά την κοινοποίηση μέσω Τα μαθήματά μου → Διάθεση στην κοινότητα εκτελείται πρώτα ένας έλεγχος βασισμένος σε κανόνες (πάντα, χωρίς AI). Επιβάλλει τα ελάχιστα παρακάτω· ένα σύνολο κάτω από αυτά δεν μπορεί να κοινοποιηθεί. Αν περάσει και είναι ρυθμισμένο ένα κλειδί AI, ο εκπαιδευόμενος μπορεί ΠΡΟΑΙΡΕΤΙΚΑ να ξεκινήσει έναν συμπληρωματικό έλεγχο AI (ακρίβεια μετάφρασης, ευλογοφάνεια distractors, γραμματική, επίπεδο, πολιτισμική ευαισθησία, φυσικότητα). Το βήμα AI δεν είναι ποτέ αυτόματο, απαιτεί ρητή συγκατάθεση (το περιεχόμενο μαθήματος αποστέλλεται στον ρυθμισμένο πάροχο) και δεν μπλοκάρει ποτέ την κοινοποίηση - ο έλεγχος βασισμένος σε κανόνες είναι η πύλη.
- Στο CI του repo περιεχομένου. Ένα Pull Request στο
astrapi69/adaptive-learner-contentεκτελεί το δικό τουscripts/validate_content.py(δομή έναντι του vendored, engine-καρφιτσωμένου καθρέφτη σχήματος + ελάχιστα ποιότητας) συν μια πύλη συμμόρφωσης engine (τοvalidate()τουlearn-content-engineπάνω σε κάθε μάθημα), ώστε ένα χειροκίνητο PR να μην μπορεί να παρακάμψει την πύλη.
Ελάχιστα ποιότητας (σκληρή πύλη): ≥ 5 ασκήσεις ανά μάθημα, ≥ 2 τύποι ασκήσεων, ≥ 1 βήμα θεωρίας, Free-Text ≥ 2 αποδεκτές απαντήσεις + distractors, Matching ≥ 3 ζεύγη, Picture-Choice με distractors, καμία κενή μπροστινή/πίσω όψη καρτών και (σε μη λατινικές γραφές αφετηρίας) πίσω όψεις καρτών στη γραφή αφετηρίας. Αυτά είναι ελάχιστα, όχι στόχοι - η λίστα ελέγχου παραπάνω απαιτεί περισσότερα.
Έλεγχος περιεχομένου με AI σε όλο το σύνολο (προαιρετικός)¶
Πέρα από τον έλεγχο κατά την κοινοποίηση, ένα κατεβασμένο σύνολο μπορεί να ελεγχθεί σε επίπεδο συνόλου μέσω Έλεγχος με AI. Αυτό είναι πλήρως προαιρετικό και χρησιμοποιεί τον πάροχο + μοντέλο που έχει ρυθμίσει ο εκπαιδευόμενος (Anthropic / OpenAI / Gemini)· οι κάρτες αποστέλλονται σε παρτίδες σε εκείνον τον πάροχο για έλεγχο. Η ροή δείχνει μια εκτίμηση κόστους, τρέχει με μπάρα προόδου + ακύρωση, και παράγει μια αναφορά ανά κάρτα που cache-άρεται στον browser και μπορεί να εξαχθεί ως Markdown (με μια γραμμή που καταγράφει ποιος πάροχος + μοντέλο έτρεξε τον έλεγχο). Όταν η αναφορά περάσει, το σύνολο κερδίζει ένα σήμα «AI-Checked» υποστηριγμένο από ένα content hash + μια υπογραφή, ώστε μια μεταγενέστερη επεξεργασία στις κάρτες να ακυρώνει το σήμα μέχρι το σύνολο να ξαναελεγχθεί. Ο έλεγχος AI δεν είναι ποτέ πύλη - είναι συμβουλευτική προέλευση, όχι απαίτηση δημοσίευσης.
Τοπικός έλεγχος¶
Ο επικυρωτής σχήματος του Content-Loader εκτελείται στο πλαίσιο του
make test. Επικύρωσε ένα μεμονωμένο μάθημα χειροκίνητα:
cd plugins/adaptive-learner-plugin-content-loader
poetry run python -c "
import json, sys
from adaptive_learner_content_loader.schema import dict_to_lesson
path = '../adaptive-learner-content/sets/en/fr-a1/lessons/01-greetings.json'
with open(path) as f:
lesson = dict_to_lesson(json.load(f))
print(f'OK: {lesson.id} - {len(lesson.cards)} Cards, {len(lesson.steps)} Steps')
"
Επικύρωσε όλα τα μαθήματα ενός repo περιεχομένου με τη μία - με τον επικυρωτή του repo περιεχομένου (το ίδιο script που εκτελεί το CI του σε κάθε PR):
Βρίσκει κάθε σύνολο κάτω από sets/{source}/{target-level}/ και ελέγχει
το σχήμα συν τα ελάχιστα ποιότητας (≥5 ασκήσεις, ≥2 τύποι ασκήσεων, ≥1
βήμα θεωρίας, Accepts free-text + distractors, ζεύγη matching, καμία
κενή κάρτα, ακεραιότητα Card-ID). Τα νέα μαθήματα αναγνωρίζονται αυτόματα -
καμία αλλαγή test δεν χρειάζεται.
Ροή εργασίας PR¶
Μόλις το σύνολό σου είναι έτοιμο:
- Άνοιξε ένα PR έναντι του κύριου repo (για σύνολα που πρόκειται να αποσταλούν με την εφαρμογή), Ή
- Δημιούργησε ένα δικό σου repo περιεχομένου κάτω από τον λογαριασμό σου
στο GitHub και ρύθμισε τον Content-Loader μέσω
backend/config/plugins/content-loader.yaml(κάτω απόdefault_sources).
Ο Content-Loader υποστηρίζει οποιοδήποτε δημόσιο GitHub-Repo ως πηγή. Τα
ιδιωτικά repos απαιτούν ένα Personal Access Token, που ορίζεται μέσω της
διαχείρισης κλειδιού τριών επιπέδων
(~/.config/adaptive_learner/secrets.yaml).
Συχνές παγίδες¶
Αναφορές Card-ID: Κάθε καταχώρηση card_ids σε μια άσκηση πρέπει να
υπάρχει στο cards[] του μαθήματος. Αν αντιγράψεις μια άσκηση μεταξύ
μαθημάτων και ξεχάσεις να πάρεις μαζί τη σχετική Card, η επικύρωση
αποτυγχάνει.
IDs ασφαλή για slug: Όλα τα IDs (Lesson, Card, Step, Exercise)
πρέπει να ταιριάζουν με ^[a-z0-9]+(-[a-z0-9]+)*$. Καμία κάτω παύλα,
καμία απόστροφος, κανένα κεφαλαίο γράμμα, καμία προηγούμενη/τελική
παύλα.
is_correct: "true": Είναι ένα String, όχι Boolean JSON. Το σχήμα
απαιτεί ρητά "true", επειδή τα πεδία picture_choice μοντελοποιούνται
εσωτερικά ως dict[str, str].
Πρόσθετα πεδία: Κάθε μοντέλο έχει extra="forbid". Ένα μη
τεκμηριωμένο πεδίο οδηγεί στην απόρριψη ολόκληρου του μαθήματος. Μείνε
στα τεκμηριωμένα πεδία.
Theory-Body: Τα Theory-Steps χρειάζονται ένα μη κενό πεδίο body
(Markdown). Τα Exercise-Steps δεν επιτρέπεται να φέρουν body - χρησιμοποίησε
αντ' αυτού το prompt της άσκησης.
Αναφορά: τα ενσωματωμένα σύνολα¶
Ο Adaptive Learner αποστέλλει μια αξιόλογη βιβλιοθήκη σε πολλούς τομείς
(γλώσσες, προγραμματισμός, ψυχολογία, τεχνητή νοημοσύνη, τεχνολογία -
δες το μπλοκ CONTENT-STATS του README για τους ζωντανούς αριθμούς + τον
πλήρη πίνακα ανά σύνολο). Μερικές καλές κανονικές αναφορές στο repo
adaptive-learner-content:
sets/en/fr-a1/- Γαλλικά A1 για Αγγλόφωνους· τοsets/de/fr-a1/είναι το γερμανόφωνο αντίστοιχο.sets/en/es-a1/+sets/de/es-a1/- Ισπανικά A1 (ένα ανά γλώσσα αφετηρίας).- Το σύνολο «Python - Grundlagen» κάτω από το
sets/de/είναι ένα παράδειγμαdomain: programming(γλώσσα αφετηρίας == στόχος), χρήσιμο ως μη γλωσσική αναφορά.
Όλα ακολουθούν τις συμβάσεις που περιγράφονται σε αυτόν τον οδηγό. Το να διαβάσεις ένα ολόκληρο μάθημα είναι ο γρηγορότερος τρόπος να αφομοιώσεις τη δομή.
Δρόμος προς τη συμμετοχή της κοινότητας (v1.42.0)¶
Αναλυτική περιήγηση βήμα προς βήμα με στιγμιότυπα: Create a lesson in the app, step by step (Medium) περιγράφει τον Lesson Creator μέσα στην εφαρμογή από άκρη σε άκρη, από την πρώτη κάρτα έως την κοινοποίηση του ολοκληρωμένου μαθήματος.
Δεν χρειάζεται να δημιουργείς μαθήματα από το μηδέν χειροκίνητα. Ο γρηγορότερος τρόπος να συνεισφέρεις είναι να δημιουργήσεις και να μοιραστείς ένα μάθημα στην εφαρμογή:
- Εισήγαγε ένα chat και ανάλυσέ το, μετά Αποθήκευση ως μάθημα Offline (ή ολοκλήρωσε ένα προσαρμοστικό μάθημα και Αποθήκευση αυτού του μαθήματος;). Το μάθημα εμφανίζεται κάτω από Τα μαθήματά μου στον Set-Browser.
- Κάνε κλικ στα «Τα μαθήματά μου» στο Εξαγωγή ως Content-Set, για να
κατεβάσεις ένα Content-Set ως
.zip(Manifest + μαθήματα). Οι εξαγωγές περιέχουν μόνο το περιεχόμενο μαθήματος - καμία πρόοδο, καμία ιστορία σφαλμάτων, τίποτα προσωπικό. - Κάνε κλικ στο Διάθεση στην κοινότητα, για να ανοίξεις ένα
προσυμπληρωμένο Pull Request στο repository περιεχομένου - το JSON
μαθήματος γίνεται commit στη σωστή διαδρομή του δέντρου, χωρίς ανάγκη
επισύναψης
.zip. - Το CI του repo επικυρώνει το PR αυτόματα· ένας maintainer ελέγχει το
μάθημα, εναρμονίζει το manifest (id, title, language, level, tags) με
τις παραπάνω συμβάσεις και το συγχωνεύει κάτω από
sets/. Μετά τη συγχώνευση όλοι μπορούν να το κατεβάσουν από τον Set-Browser.
Αυτός είναι ο κοινωνικός δρόμος: Ο έλεγχος είναι χειροκίνητος (ένας maintainer επιμελείται κάθε προσθήκη - τίποτα δεν δημοσιεύεται αυτόματα), και όλη η ροή χρειάζεται μόνο το GitHub. Τα δημιουργημένα μαθήματα επικυρώνονται ήδη έναντι του σχήματος, ώστε ένα μάθημα που συνεισφέρεται συνήθως χρειάζεται μόνο λίγη λείανση manifest.
Οδηγός κοινοποίησης, παραλλαγές και Credit συντάκτη (Φάση 64)¶
Η κοινοποίηση ενός μαθήματος από τα Τα μαθήματά μου ανοίγει έναν οδηγό τεσσάρων σταδίων, αντί να μεταβαίνει απευθείας στο GitHub:
- Προεπισκόπηση + τοποθέτηση. Η εφαρμογή υπολογίζει ακριβώς πού
προσγειώνεται το μάθημα στο δέντρο (
sets/{source}/{target}-{level}/) και ένα αυτόματα αριθμημένο όνομα αρχείου ({nn}-{slug}.json, ο επόμενος αριθμός μετά τα υπάρχοντα μαθήματα). Ένα εντελώς νέο ζεύγος + επίπεδο δείχνει «Νέο σύνολο! Είσαι ο πρώτος.» - Έλεγχος διπλότυπων. Το μάθημα συγκρίνεται με τα ήδη υπάρχοντα μαθήματα σε αυτή τη διαδρομή (επικάλυψη καρτών και ασκήσεων - συμβουλευτική, ποτέ αποκλειστική). Αν υπάρχει κάτι παρόμοιο, μπορείς να:
- Κοινοποιήσεις ως παραλλαγή - το μάθημα σημειώνεται με
variation_of: "{original_id}"συν ένα προαιρετικόvariation_note(«Σε τι διαφέρει η εκδοχή σου;»). - Προτείνεις μόνο τις νέες ασκήσεις (σε σχεδόν διπλότυπα) - ο οδηγός εξάγει ακριβώς τις ασκήσεις που λείπουν από το πρωτότυπο, μαζί με τις σχετικές κάρτες, ως παραλλαγή συμπλήρωσης.
- Σύνοψη ποιότητας. Τα ευρήματα του επικυρωτή βασισμένου σε κανόνες (συν ο προαιρετικός έλεγχος AI)· οι προειδοποιήσεις εμφανίζονται, αλλά δεν μπλοκάρουν ποτέ.
- Κοινοποίηση + γιορτή. Ένα κλικ ανοίγει το GitHub-Pull-Request (επεξεργαστής αρχείου σε μικρά μαθήματα, σελίδα Upload σε μεγάλα), και η εφαρμογή σε ευχαριστεί με μια μικρή γιορτή.
Πεδία παραλλαγών και Credit (Σχήμα 1.3, όλα προαιρετικά)¶
{
"variation_of": "10-passe-compose",
"variation_note": "Mehr Übungen zur Angleichung",
"contributed_by": "Maria S.",
"contributed_at": "2026-06-01T14:30:00Z"
}
Και τα τέσσερα είναι additive και προαιρετικά· μαθήματα χωρίς αυτά
συμπεριφέρονται ακριβώς όπως πριν. Το contributed_by ορίζεται, όταν ο
συντάκτης ενεργοποιεί το Credit κατά την κοινοποίηση (ένα πεδίο «Το
όνομά σου (προαιρετικό)», που απομνημονεύεται τοπικά για την επόμενη
φορά). Αν υπάρχει, ο προβολέας εμφανίζει μια διακριτική γραμμή
«Διατέθηκε από {name}» κάτω από τον τίτλο, και το κείμενο του
Pull-Request αναφέρει τον συντάκτη στον πίνακα μεταδεδομένων του.
Ιστορικό συνεισφορών και κενά¶
Τα κοινοποιημένα μαθήματα απομνημονεύονται τοπικά (κανένας λογαριασμός δεν χρειάζεται) κάτω από Οι συνεισφορές μου με έναν μετρητή και μια διάκριση Συνεισφέρων κοινότητας από πέντε κοινοποιημένα μαθήματα και άνω. Ο Set-Browser εμφανίζει επιπλέον Μαθήματα που λείπουν - ενθαρρυντικές προτάσεις για το επόμενο επίπεδο CEFR ενός υπάρχοντος ζεύγους ή μια γλώσσα στόχο, που υπάρχει για μια γλώσσα αφετηρίας, αλλά λείπει για μια άλλη («Μπορείς να βοηθήσεις;»).
Σχετικές σελίδες¶
- Δημιουργία μαθημάτων - Επισκόπηση - εισαγωγή + ο Lesson Creator μέσα στην εφαρμογή
- Προτάσεις βιβλίων - συντήρηση του
books.yamlανά τομέα - Πολλαπλά Content-Repositories - σύνδεση δικού σου repo
- Create a lesson in the app, step by step - εξωτερική περιήγηση Medium με στιγμιότυπα