rubric
هو نموذج يمكن للمعلّمين استخدامه عند وضع الدرجات على مواد التقييم التي يقدّمها الطلاب. تتيح لك Classroom API التصرف نيابةً عن
المعلّم لإدارة هذه التصنيفات، بالإضافة إلى قراءة الدرجات وفقًا للتصنيفات على ملفّات التحميل التي يرسلها
الطلاب.
الشكل 1. عرض نموذج لقواعد التقييم في مهمة على Classroom
يشرح هذا الدليل المفاهيم الأساسية ووظائف Rubrics API. اطّلِع على مقالات مركز المساعدة هذه للتعرّف على البنية العامة لقواعد التقييم وكيفية تقييم قواعد التقييم في واجهة مستخدم Classroom.
المتطلبات الأساسية
يفترض هذا الدليل أنّك تستوفي الشروط التالية:
- الإصدار 3.8.6 من Python أو إصدار أحدث
- أداة إدارة الحِزم pip
- مشروع على Google Cloud
- حساب Google Workspace for Education تم تفعيل Google Classroom فيه وتم إسناد ترخيص Google Workspace for Education Plus إليه يمكنك طلب ترقية حساب المطوِّر التجريبي إذا لم يكن لديك حساب.
- صف اختباري يتضمّن حساب طالب اختباري واحدًا على الأقل إذا لم يكن لديك صف في Classroom يمكنك استخدامه للاختبار، أنشئ صفًا في واجهة المستخدم و أضِف طالبًا اختباريًا.
تفويض بيانات الاعتماد لتطبيق على الكمبيوتر المكتبي
لمصادقة المستخدم النهائي والوصول إلى بياناته في تطبيقك، عليك إنشاء معرّف عميل واحد أو أكثر من معرّفات OAuth 2.0. يُستخدَم معرّف العميل لتحديد تطبيق واحد على خوادم OAuth في Google. إذا كان تطبيقك يعمل على منصات متعددة، يجب إنشاء معرّف عميل منفصل لكل منصة.
- انتقِل إلى صفحة بيانات الاعتماد في Google Cloud في وحدة تحكّم Google Cloud.
- انقر على إنشاء بيانات اعتماد > معرِّف عميل OAuth.
- انقر على نوع التطبيق > تطبيق كمبيوتر مكتبي.
- في حقل الاسم، اكتب اسمًا لبيانات الاعتماد. ولا يظهر هذا الاسم إلا في "وحدة تحكّم Google Cloud". على سبيل المثال، "عميل العناوين".
- انقر على إنشاء. تظهر شاشة "تم إنشاء عميل OAuth"، وتعرض معرّف العميل وسرّه الجديدَين.
- انقر على تنزيل ملف JSON، ثم على حسنًا. تظهر بيانات الاعتماد التي تم إنشاؤها حديثًا ضمن معرّفات عملاء OAuth 2.0.
- احفظ ملف JSON الذي تم تنزيله باسم
credentials.json
، وانقل الملف إلى دليل العمل. - انقر على إنشاء بيانات اعتماد > مفتاح واجهة برمجة التطبيقات ودوِّن مفتاح واجهة برمجة التطبيقات.
اطّلِع على إنشاء بيانات اعتماد الوصول لمعرفة المزيد.
ضبط نطاقات OAuth
استنادًا إلى نطاقات OAuth الحالية لمشروعك، قد تحتاج إلى ضبط نطاقات إضافية.
- انتقِل إلى شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth.
- انقر على تعديل التطبيق > حفظ ومتابعة للوصول إلى شاشة "النطاقات".
- انقر على إضافة نطاقات أو إزالتها.
- أضِف النطاقات التالية إذا لم تكن لديك:
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.courses
- بعد ذلك، انقر على "تعديل" > حفظ ومتابعة > حفظ ومتابعة > الرجوع إلى لوحة البيانات.
اطّلِع على مقالة ضبط شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth للتعرّف على معلومات إضافية.
يتيح نطاق classroom.coursework.students
الوصول للقراءة والكتابة إلى
المخطّطات (بالإضافة إلى الوصول إلى CourseWork
)، ويتيح نطاق classroom.courses
قراءة الدورات التدريبية وكتابتها.
يتم إدراج النطاقات المطلوبة لطريقة معيّنة في المستندات المرجعية
للطريقة. يمكنك الاطّلاع على courses.courseWork.rubrics.create
نطاقات التفويض
كمثال. يمكنك الاطّلاع على جميع نطاقات Classroom في نطاقات OAuth 2.0 لواجهات Google
APIs.
ضبط العيّنة
في دليل العمل، ثبِّت مكتبة عملاء Google لبرنامج Python:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
أنشئ ملفًا باسم main.py
ينشئ مكتبة العميل ويمنح الإذن
للمستخدم، باستخدام مفتاح واجهة برمجة التطبيقات بدلاً من YOUR_API_KEY
:
import json
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/classroom.courses',
'https://www.googleapis.com/auth/classroom.coursework.students']
def build_authenticated_service(api_key):
"""Builds the Classroom service."""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run.
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
# Build the Classroom service.
service = build(
serviceName="classroom",
version="v1",
credentials=creds,
discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=DEVELOPER_PREVIEW&key={api_key}")
return service
except HttpError as error:
print('An error occurred: %s' % error)
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
شغِّل النص البرمجي باستخدام python main.py
. سيُطلب منك تسجيل الدخول ومنح الموافقة على نطاقات OAuth.
إنشاء مهمة دراسية
يكون مقياس التقييم مرتبطًا بمهمة أو CourseWork
، ولا يكون له قيمة إلا في سياق هذا CourseWork
. لا يمكن إنشاء العناوين إلا من قِبل
مشروع Google Cloud الذي أنشأ العنصرCourseWork
الرئيسي. لأغراض
هذا الدليل، أنشئ مهمة CourseWork
جديدة باستخدام نص برمجي.
أضِف ما يلي إلى main.py
:
def get_latest_course(service):
"""Retrieves the last created course."""
try:
response = service.courses().list(pageSize=1).execute()
courses = response.get("courses", [])
if not courses:
print("No courses found. Did you remember to create one in the UI?")
return
course = courses[0]
return course
except HttpError as error:
print(f"An error occurred: {error}")
return error
def create_coursework(service, course_id):
"""Creates and returns a sample coursework."""
try:
coursework = {
"title": "Romeo and Juliet analysis.",
"description": """Write a paper arguing that Romeo and Juliet were
time travelers from the future.""",
"workType": "ASSIGNMENT",
"state": "PUBLISHED",
}
coursework = service.courses().courseWork().create(
courseId=course_id, body=coursework).execute()
return coursework
except HttpError as error:
print(f"An error occurred: {error}")
return error
عدِّل الآن main.py
لاسترداد course_id
لفئة الاختبار التي أنشأتها
توًا، وأنشئ نموذج مهمة جديدًا، واسترِد coursework_id
المهمة:
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
course = get_latest_course(service)
course_id = course.get("id")
course_name = course.get("name")
print(f"'{course_name}' course ID: {course_id}")
coursework = create_coursework(service, course_id)
coursework_id = coursework.get("id")
print(f"Assignment created with ID {coursework_id}")
#TODO(developer): Save the printed course and coursework IDs.
احفظ course_id
وcoursework_id
. هذه السمات مطلوبة لجميع عمليات CRUD
في العناوين.
من المفترض أن يكون لديك الآن نموذج CourseWork
في Classroom.
الشكل 2: عرض نموذج لمهمة في Classroom
التحقّق من أهلية المستخدم
يتطلب إنشاء قوائم التقييم وتعديلها أن يكون لدى كلّ من المستخدم الذي يقدّم الطلب ومالك الدورة التدريبية المعنيّ ترخيص Google Workspace for Education Plus. تتيح Classroom استخدام نقطة نهاية أهلية للمستخدمين من أجل تمكين المطوّرين من تحديد الميزات التي يمكن للمستخدم الوصول إليها.
عدِّل main.py
وشغِّله للتأكّد من أنّ حسابك التجريبي يمكنه الوصول إلى ميزة
المخطّطات:
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
capability = service.userProfiles().checkUserCapability(
userId='me',
# Specify the preview version. checkUserCapability is
# supported in V1_20240930_PREVIEW and later.
previewVersion="V1_20240930_PREVIEW",
capability="CREATE_RUBRIC").execute()
if not capability.get('allowed'):
print('User ineligible for rubrics creation.')
# TODO(developer): in a production app, this signal could be used to
# proactively hide any rubrics related features from users or encourage
# them to upgrade to the appropriate license.
else:
print('User eligible for rubrics creation.')
إنشاء قواعد تقييم
أنت الآن جاهز لبدء إدارة العناوين الرئيسية.
يمكن إنشاء مقياس تقييم في CourseWork
باستخدام طلب create()
يحتوي على
عنصر المقياس التقييمي الكامل، حيث يتم حذف سمات المعرّفات للمعايير والمستويات (يتم إنشاؤها عند الإنشاء).
أضِف الدالة التالية إلى main.py
:
def create_rubric(service, course_id, coursework_id):
"""Creates an example rubric on a coursework."""
try:
body = {
"criteria": [
{
"title": "Argument",
"description": "How well structured your argument is.",
"levels": [
{"title": "Convincing",
"description": "A compelling case is made.", "points": 30},
{"title": "Passable",
"description": "Missing some evidence.", "points": 20},
{"title": "Needs Work",
"description": "Not enough strong evidence..", "points": 0},
]
},
{
"title": "Spelling",
"description": "How well you spelled all the words.",
"levels": [
{"title": "Perfect",
"description": "No mistakes.", "points": 20},
{"title": "Great",
"description": "A mistake or two.", "points": 15},
{"title": "Needs Work",
"description": "Many mistakes.", "points": 5},
]
},
{
"title": "Grammar",
"description": "How grammatically correct your sentences are.",
"levels": [
{"title": "Perfect",
"description": "No mistakes.", "points": 20},
{"title": "Great",
"description": "A mistake or two.", "points": 15},
{"title": "Needs Work",
"description": "Many mistakes.", "points": 5},
]
},
]
}
rubric = service.courses().courseWork().rubrics().create(
courseId=course_id, courseWorkId=coursework_id, body=body
).execute()
print(f"Rubric created with ID {rubric.get('id')}")
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error
بعد ذلك، عدِّل main.py
وشغِّله لإنشاء مثال على مقياس الأداء، باستخدام معرّفي Course
وCourseWork
من الخطوات السابقة:
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
capability = service.userProfiles().checkUserCapability(
userId='me',
# Specify the preview version. checkUserCapability is
# supported in V1_20240930_PREVIEW and later.
previewVersion="V1_20240930_PREVIEW",
capability="CREATE_RUBRIC").execute()
if not capability.get('allowed'):
print('User ineligible for rubrics creation.')
# TODO(developer): in a production app, this signal could be used to
# proactively hide any rubrics related features from users or encourage
# them to upgrade to the appropriate license.
else:
rubric = create_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
print(json.dumps(rubric, indent=4))
في ما يلي بعض النقاط حول تمثيل المقياس:
- يظهر ترتيب المعايير والمستويات في واجهة مستخدم Classroom.
- يجب ترتيب المستويات التي تم احتساب نقاط لها (تلك التي تحتوي على السمة
points
) حسب النقاط سواءً بترتيب تصاعدي أو تنازلي (لا يمكن ترتيبها عشوائيًا). - يمكن للمعلّمين إعادة ترتيب المعايير والمستويات التي تم احتساب نقاط لها (وليس المستويات التي لم يتم احتساب نقاط لها) في واجهة المستخدم، ما يؤدي إلى تغيير ترتيبها في البيانات.
اطّلِع على القيود لمعرفة المزيد من التحذيرات حول بنية العناوين الرئيسية.
في واجهة المستخدم، من المفترض أن يظهر لك مقياس التقييم في المهمة.
الشكل 3: عرض نموذج لقواعد التقييم في مهمة على Classroom
قراءة قواعد التقييم
يمكن قراءة العناوين باستخدام الطريقتَين العاديتَين list()
وget()
.
يمكن أن يكون هناك مقياس واحد فقط في كل مهمة، لذلك قد يبدو الخيار list()
غير واضح، ولكنه مفيد إذا لم يكن لديك رقم تعريف المقياس. إذا لم يكن هناك CourseWork
مرتبط بتقييم، يكون الحقل list()
فارغًا.
أضِف الدالة التالية إلى main.py
:
def get_rubric(service, course_id, coursework_id):
"""
Get the rubric on a coursework. There can only be at most one.
Returns null if there is no rubric.
"""
try:
response = service.courses().courseWork().rubrics().list(
courseId=course_id, courseWorkId=coursework_id
).execute()
rubrics = response.get("rubrics", [])
if not rubrics:
print("No rubric found for this assignment.")
return
rubric = rubrics[0]
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error
عدِّل main.py
وشغِّله للحصول على المخطّط الذي أضفته:
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
print(json.dumps(rubric, indent=4))
#TODO(developer): Save the printed rubric ID.
سجِّل موقع id
في قسم العناوين للخطوات اللاحقة.
يعمل Get()
بشكل جيد عندما يكون لديك رقم تعريف المقياس. قد يبدو استخدام get()
في الدالة
بدلاً من ذلك على النحو التالي:
def get_rubric(service, course_id, coursework_id, rubric_id):
"""
Get the rubric on a coursework. There can only be at most one.
Returns a 404 if there is no rubric.
"""
try:
rubric = service.courses().courseWork().rubrics().get(
courseId=course_id,
courseWorkId=coursework_id,
id=rubric_id
).execute()
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error
يعرض هذا التنفيذ رسالة الخطأ 404 في حال عدم توفّر مقياس.
تعديل قواعد التقييم
يتم إجراء التعديلات على مقياس التقييم من خلال مكالمات patch()
. بسبب البنية
المعقدة للنموذج، يجب إجراء التعديلات باستخدام نمط القراءة والتعديل والكتابة،
حيث يتم استبدال سمة criteria
بالكامل.
في ما يلي قواعد التعديل:
- تُعتبر المعايير أو المستويات المُضافة بدون رقم تعريف إضافات.
- إنّ المعايير أو المستويات غير المتوفّرة من قبل تُعدّ عمليات حذف.
- تُعتبَر المعايير أو المستويات التي تتضمّن معرّفًا حاليًا ولكنّها تتضمّن بيانات معدَّلة تعديلات. ويتم ترك السمات غير المعدَّلة كما هي.
- تُعتبَر المعايير أو المستويات التي يتم تقديمها باستخدام معرّفات جديدة أو غير معروفة أخطاء.
- يُعدّ ترتيب المعايير والمستويات الجديدة هو ترتيب واجهة المستخدم الجديدة (مع القيود المذكورة أعلاه).
أضِف دالة لتعديل قواعد التقييم:
def update_rubric(service, course_id, coursework_id, rubric_id, body):
"""
Updates the rubric on a coursework.
"""
try:
rubric = service.courses().courseWork().rubrics().patch(
courseId=course_id,
courseWorkId=coursework_id,
id=rubric_id,
body=body,
updateMask='criteria'
).execute()
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error
في هذا المثال، تم تحديد الحقل criteria
للتعديل باستخدام
updateMask
.
بعد ذلك، عدِّل main.py
لإجراء تغيير في كلّ من قواعد التحديث
المذكورة أعلاه:
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
capability = service.userProfiles().checkUserCapability(
userId='me',
# Specify the preview version. checkUserCapability is
# supported in V1_20240930_PREVIEW and later.
previewVersion="V1_20240930_PREVIEW",
capability="CREATE_RUBRIC").execute()
if not capability.get('allowed'):
print('User ineligible for rubrics creation.')
# TODO(developer): in a production app, this signal could be used to
# proactively hide any rubrics related features from users or encourage
# them to upgrade to the appropriate license.
else:
# Get the latest rubric.
rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
criteria = rubric.get("criteria")
"""
The "criteria" property should look like this:
[
{
"id": "NkEyMdMyMzM2Nxkw",
"title": "Argument",
"description": "How well structured your argument is.",
"levels": [
{
"id": "NkEyMdMyMzM2Nxkx",
"title": "Convincing",
"description": "A compelling case is made.",
"points": 30
},
{
"id": "NkEyMdMyMzM2Nxky",
"title": "Passable",
"description": "Missing some evidence.",
"points": 20
},
{
"id": "NkEyMdMyMzM2Nxkz",
"title": "Needs Work",
"description": "Not enough strong evidence..",
"points": 0
}
]
},
{
"id": "NkEyMdMyMzM2Nxk0",
"title": "Spelling",
"description": "How well you spelled all the words.",
"levels": [...]
},
{
"id": "NkEyMdMyMzM2Nxk4",
"title": "Grammar",
"description": "How grammatically correct your sentences are.",
"levels": [...]
}
]
"""
# Make edits. This example will make one of each type of change.
# Add a new level to the first criteria. Levels must remain sorted by
# points.
new_level = {
"title": "Profound",
"description": "Truly unique insight.",
"points": 50
}
criteria[0]["levels"].insert(0, new_level)
# Remove the last criteria.
del criteria[-1]
# Update the criteria titles with numeric prefixes.
for index, criterion in enumerate(criteria):
criterion["title"] = f"{index}: {criterion['title']}"
# Resort the levels from descending to ascending points.
for criterion in criteria:
criterion["levels"].sort(key=lambda level: level["points"])
# Update the rubric with a patch call.
new_rubric = update_rubric(
service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID, YOUR_RUBRIC_ID, rubric)
print(json.dumps(new_rubric, indent=4))
من المفترض أن تظهر التغييرات الآن للمعلّم في Classroom.
الشكل 4. عرض قاعدة التقييم المعدّلة
عرض التقييمات المُرسَلة استنادًا إلى قواعد التقييم
في الوقت الحالي، لا يمكن استخدام واجهة برمجة التطبيقات لمنح الدرجات للطلاب استنادًا إلى قواعد التقييم، ولكن يمكنك قراءة درجات قواعد التقييم للمهام التي تم منحها درجة استنادًا إلى قواعد التقييم في واجهة مستخدم Classroom.
بصفتك طالبًا في واجهة مستخدم Classroom، أكمِل نموذج المهمة الدراسية وأرسِله. بعد ذلك، يمكن للمعلّم وضع الدرجات يدويًا للمهمة باستخدام مقياس التقييم.
الشكل 5: طريقة عرض المعلّم لقواعد التقييم أثناء وضع الدرجات
إنّ StudentSubmissions
التي تم وضع علامات لها باستخدام نموذج تقييم تتضمّن سمتَين جديدتَين: draftRubricGrades
وassignedRubricGrades
، اللتان تمثّلان النقاط والمستويات التي اختارها المعلّم أثناء مرحلة المسودة وحالات وضع العلامات المخصّصة، على التوالي.
يمكنك استخدام الطريقتَين الحاليتَين studentSubmissions.get()
و
studentSubmissions.list()
لعرض المراجعات التي تم تقييمها.
أضِف الدالة التالية إلى main.py
لعرض المهام التي أرسلها الطلاب:
def get_latest_submission(service, course_id, coursework_id):
"""Retrieves the last submission for an assignment."""
try:
response = service.courses().courseWork().studentSubmissions().list(
courseId = course_id,
courseWorkId = coursework_id,
pageSize=1
).execute()
submissions = response.get("studentSubmissions", [])
if not submissions:
print(
"""No submissions found. Did you remember to turn in and grade
the assignment in the UI?""")
return
submission = submissions[0]
return submission
except HttpError as error:
print(f"An error occurred: {error}")
return error
بعد ذلك، عدِّل main.py
وشغِّله للاطّلاع على درجات الإرسال.
if __name__ == '__main__':
service = build_authenticated_service(YOUR_API_KEY)
submission = get_latest_submission(
service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
print(json.dumps(submission, indent=4))
يحتوي draftRubricGrades
وassignedRubricGrades
على ما يلي:
criterionId
لمعايير قواعد التقييم المقابلة.points
التي حدّدها المعلّم لكل معيار قد يرجع ذلك إلى المستوى المحدّد، ولكن من المحتمل أيضًا أن يكون المعلّم قد استبدل هذا الإعداد.levelId
من المستوى الذي تم اختياره لكل معيار. إذا لم يحدد المعلّم مستوى، ولكنّه منح نقاطًا للمعيار، لن يظهر هذا الحقل.
لا تحتوي هذه القوائم إلا على إدخالات للمعايير التي إما أن يحدد فيها المعلّم مستوى أو يحدّد نقاطًا. على سبيل المثال، إذا اختار المعلّم التعامل مع معيار واحد فقط أثناء التقييم، لن يتضمّن draftRubricGrades
وassignedRubricGrades
سوى عنصر واحد، حتى إذا كانت التقييمات تحتوي على العديد من المعايير.
حذف قواعد تقييم
يمكن حذف مقياس تقييم باستخدام طلب delete()
عادي. يعرض الرمز التالي مثالاً على الدالة لإكمالها، ولكن بما أنّه سبق أن بدأ تحديد الدرجات، لا يمكنك حذف المقياس الحالي:
def delete_rubric(service, course_id, coursework_id, rubric_id):
"""Deletes the rubric on a coursework."""
try:
service.courses().courseWork().rubrics().delete(
courseId=course_id,
courseWorkId=coursework_id,
id=rubric_id
).execute()
except HttpError as error:
print(f"An error occurred: {error}")
return error
تصدير قواعد التقييم واستيرادها
يمكن تصدير قواعد التقييم يدويًا إلى "جداول بيانات Google" لإعادة استخدامها من قِبل المعلّمين.
بالإضافة إلى تحديد معايير قواعد التقييم في الرمز، من الممكن إنشاء قواعد تقييم
وتعديلها من هذه الجداول التي تم تصديرها من خلال تحديد
sourceSpreadsheetId
في نص قاعدة التقييم بدلاً من criteria
:
def create_rubric_from_sheet(service, course_id, coursework_id, sheet_id):
"""Creates an example rubric on a coursework."""
try:
body = {
"sourceSpreadsheetId": sheet_id
}
rubric = service.courses().courseWork().rubrics().create(
courseId=course_id, courseWorkId=coursework_id, body=body
).execute()
print(f"Rubric created with ID {rubric.get('id')}")
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error