rubric
là một mẫu mà giáo viên có thể sử dụng khi chấm điểm bài tập mà học viên nộp. API Lớp học cho phép bạn thay mặt giáo viên quản lý các tiêu chí này, cũng như đọc điểm theo tiêu chí trên bài nộp của học viên.
Hình 1. Chế độ xem tiêu chí chấm điểm mẫu trên một bài tập trong Lớp học.
Hướng dẫn này giải thích các khái niệm và chức năng cơ bản của API Rubrics. Hãy xem các bài viết này trên Trung tâm trợ giúp để tìm hiểu về cấu trúc chung của tiêu chí chấm điểm và cách chấm điểm theo tiêu chí trong giao diện người dùng của Lớp học.
Điều kiện tiên quyết
Hướng dẫn này giả định rằng bạn có:
- Python 3.8.6 trở lên
- Công cụ quản lý gói pip
- Một dự án trên Google Cloud.
- Tài khoản Google Workspace for Education đã bật Google Lớp học và được cấp giấy phép Google Workspace for Education Plus. Bạn có thể yêu cầu nâng cấp tài khoản minh hoạ dành cho nhà phát triển nếu chưa có tài khoản này.
- Một Lớp học thử nghiệm có ít nhất một tài khoản học viên thử nghiệm. Nếu bạn không có lớp Lớp học để kiểm thử, hãy tạo một lớp trong giao diện người dùng và thêm một học viên kiểm thử.
Uỷ quyền thông tin xác thực cho ứng dụng trên máy tính
Để xác thực dưới dạng người dùng cuối và truy cập vào dữ liệu người dùng trong ứng dụng, bạn cần tạo một hoặc nhiều mã ứng dụng khách OAuth 2.0. Mã ứng dụng khách được dùng để xác định một ứng dụng duy nhất với máy chủ OAuth của Google. Nếu ứng dụng của bạn chạy trên nhiều nền tảng, bạn phải tạo một mã ứng dụng riêng cho mỗi nền tảng.
- Chuyển đến trang Thông tin xác thực của Google Cloud trong bảng điều khiển Google Cloud.
- Nhấp vào Tạo thông tin xác thực > Mã ứng dụng khách OAuth.
- Nhấp vào Loại ứng dụng > Ứng dụng dành cho máy tính.
- Trong trường Name (Tên), hãy nhập tên cho thông tin xác thực. Tên này chỉ xuất hiện trong Google Cloud Console. Ví dụ: "Ứng dụng tiêu đề".
- Nhấp vào Tạo. Màn hình ứng dụng khách OAuth đã tạo sẽ xuất hiện, hiển thị mã ứng dụng khách và thông tin xác thực ứng dụng khách mới.
- Nhấp vào Tải JSON xuống, sau đó nhấp vào OK. Thông tin xác thực mới tạo sẽ xuất hiện trong phần Mã ứng dụng khách OAuth 2.0.
- Lưu tệp JSON đã tải xuống dưới dạng
credentials.json
và di chuyển tệp đó vào thư mục đang hoạt động. - Nhấp vào Tạo thông tin xác thực > Khoá API rồi ghi lại khoá API.
Hãy xem phần Tạo thông tin xác thực quyền truy cập để tìm hiểu thêm.
Định cấu hình phạm vi OAuth
Tuỳ thuộc vào phạm vi OAuth hiện có của dự án, bạn có thể cần định cấu hình các phạm vi bổ sung.
- Chuyển đến màn hình xin phép bằng OAuth.
- Nhấp vào Chỉnh sửa ứng dụng > Lưu và tiếp tục để chuyển đến màn hình Phạm vi.
- Nhấp vào Thêm hoặc xoá phạm vi.
- Thêm các phạm vi sau nếu bạn chưa có:
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.courses
- Sau đó, Nhấp vào Cập nhật > Lưu và tiếp tục > Lưu và tiếp tục > Quay lại trang tổng quan.
Hãy xem bài viết Định cấu hình màn hình xin phép bằng OAuth để tìm hiểu thêm.
Phạm vi classroom.coursework.students
cho phép quyền đọc và ghi vào tiêu chí (cùng với quyền truy cập vào CourseWork
), còn phạm vi classroom.courses
cho phép đọc và ghi khoá học.
Các phạm vi bắt buộc cho một phương thức nhất định được liệt kê trong tài liệu tham khảo cho phương thức đó. Hãy xem phạm vi uỷ quyền courses.courseWork.rubrics.create
làm ví dụ. Bạn có thể xem tất cả phạm vi của Lớp học trong phần Phạm vi OAuth 2.0 cho các API của Google.
Định cấu hình mẫu
Trong thư mục đang hoạt động, hãy cài đặt thư viện ứng dụng Google cho Python:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
Tạo một tệp có tên là main.py
để tạo thư viện ứng dụng và uỷ quyền cho người dùng, sử dụng khoá API thay cho 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)
Chạy tập lệnh bằng python main.py
. Bạn sẽ được nhắc đăng nhập và đồng ý với các phạm vi OAuth.
Tạo bài tập
Bảng điểm được liên kết với một bài tập hoặc CourseWork
và chỉ có ý nghĩa trong ngữ cảnh của CourseWork
đó. Chỉ dự án Google Cloud đã tạo mục CourseWork
mẹ mới có thể tạo tiêu đề. Để phục vụ mục đích của hướng dẫn này, hãy tạo một bài tập CourseWork
mới bằng một tập lệnh.
Thêm nội dung sau vào 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
Bây giờ, hãy cập nhật main.py
để truy xuất course_id
của lớp kiểm thử bạn vừa tạo, tạo một bài tập mẫu mới và truy xuất coursework_id
của bài tập:
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.
Lưu course_id
và coursework_id
. Các thuộc tính này cần thiết cho tất cả các thao tác CRUD của tiêu chí.
Bây giờ, bạn sẽ có một CourseWork
mẫu trong Lớp học.
Hình 2. Chế độ xem bài tập mẫu trong Lớp học.
Kiểm tra xem người dùng có đủ điều kiện hay không
Để tạo và cập nhật thang điểm, cả người dùng đưa ra yêu cầu và chủ sở hữu khoá học tương ứng đều phải có giấy phép Google Workspace for Education Plus. Lớp học hỗ trợ điểm cuối đủ điều kiện của người dùng để cho phép nhà phát triển xác định các tính năng mà người dùng có quyền truy cập.
Cập nhật và chạy main.py
để xác nhận rằng tài khoản thử nghiệm của bạn có quyền truy cập vào tính năng điểm chuẩn:
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.')
Tạo tiêu chí chấm điểm
Giờ đây, bạn đã có thể bắt đầu quản lý thang điểm.
Bạn có thể tạo một thang điểm trên CourseWork
bằng lệnh gọi create()
chứa đối tượng thang điểm đầy đủ, trong đó các thuộc tính mã nhận dạng cho tiêu chí và cấp độ bị bỏ qua (các thuộc tính này được tạo khi tạo).
Thêm hàm sau vào 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
Sau đó, hãy cập nhật và chạy main.py
để tạo thang điểm mẫu, sử dụng mã Course
và CourseWork
trước đó:
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))
Một số điểm về cách trình bày tiêu chí chấm điểm:
- Tiêu chí và thứ tự cấp sẽ được phản ánh trong giao diện người dùng của Lớp học.
- Các cấp có điểm (những cấp có thuộc tính
points
) phải được sắp xếp theo điểm theo thứ tự tăng dần hoặc giảm dần (không thể sắp xếp ngẫu nhiên). - Giáo viên có thể sắp xếp lại các tiêu chí và cấp có điểm (nhưng không phải cấp không có điểm) trong giao diện người dùng. Việc này sẽ thay đổi thứ tự của các tiêu chí và cấp trong dữ liệu.
Hãy xem phần các hạn chế để biết thêm lưu ý về cấu trúc của tiêu chí.
Quay lại giao diện người dùng, bạn sẽ thấy thang điểm trên bài tập.
Hình 3. Chế độ xem tiêu chí chấm điểm mẫu trên một bài tập trong Lớp học.
Đọc tiêu chí chấm điểm
Bạn có thể đọc thang điểm bằng các phương thức list()
và get()
chuẩn.
Một bài tập có thể có tối đa một tiêu chí đánh giá, vì vậy, list()
có vẻ không trực quan, nhưng sẽ hữu ích nếu bạn chưa có mã tiêu chí đánh giá. Nếu không có tiêu chí nào liên kết với CourseWork
, thì phản hồi list()
sẽ trống.
Thêm hàm sau vào 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
Cập nhật và chạy main.py
để tìm nạp tiêu chí chấm điểm mà bạn đã thêm:
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.
Lưu ý thuộc tính id
trong thang điểm cho các bước sau.
Get()
hoạt động tốt khi bạn có mã nhận dạng tiêu chí. Thay vào đó, việc sử dụng get()
trong hàm có thể có dạng như sau:
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
Phương thức triển khai này sẽ trả về mã lỗi 404 nếu không có thang điểm.
Cập nhật tiêu chí chấm điểm
Bạn có thể cập nhật thang điểm bằng các lệnh gọi patch()
. Do cấu trúc phức tạp của một thang điểm, bạn phải cập nhật bằng mẫu đọc-sửa đổi-ghi, trong đó toàn bộ thuộc tính criteria
sẽ được thay thế.
Sau đây là các quy tắc cập nhật:
- Các tiêu chí hoặc cấp được thêm mà không có mã nhận dạng được coi là thêm.
- Những tiêu chí hoặc cấp thiếu trước đó được coi là bị xoá.
- Các tiêu chí hoặc cấp có mã nhận dạng hiện có nhưng dữ liệu đã được sửa đổi được coi là bản chỉnh sửa. Các thuộc tính chưa sửa đổi sẽ được giữ nguyên.
- Các tiêu chí hoặc cấp được cung cấp bằng mã nhận dạng mới hoặc không xác định được coi là lỗi.
- Thứ tự của các tiêu chí và cấp độ mới được coi là thứ tự giao diện người dùng mới (với các giới hạn nêu trên).
Thêm một hàm để cập nhật tiêu chí chấm điểm:
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
Trong ví dụ này, trường criteria
được chỉ định để sửa đổi bằng updateMask
.
Sau đó, hãy sửa đổi main.py
để thực hiện thay đổi cho từng quy tắc cập nhật nêu trên:
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))
Những thay đổi này sẽ được phản ánh cho giáo viên trong Lớp học.
Hình 4. Chế độ xem tiêu chí chấm điểm đã cập nhật.
Xem bài nộp được chấm điểm theo tiêu chí
Hiện tại, API không thể chấm điểm bài nộp của học viên theo tiêu chí chấm điểm, nhưng bạn có thể đọc điểm theo tiêu chí chấm điểm cho những bài nộp đã được chấm điểm theo tiêu chí chấm điểm trong giao diện người dùng của Lớp học.
Với vai trò là học viên trong giao diện người dùng Lớp học, hãy hoàn thành và nộp bài tập mẫu. Sau đó, với tư cách là giáo viên, hãy chấm điểm bài tập theo tiêu chí theo cách thủ công.
Hình 5. Chế độ xem của giáo viên về tiêu chí chấm điểm trong quá trình chấm điểm.
StudentSubmissions
đã được chấm điểm bằng thang điểm có hai thuộc tính mới: draftRubricGrades
và assignedRubricGrades
, lần lượt đại diện cho điểm và cấp độ do giáo viên chọn trong bản nháp và trạng thái chấm điểm được chỉ định.
Bạn có thể sử dụng các phương thức studentSubmissions.get()
và studentSubmissions.list()
hiện có để xem bài nộp đã chấm điểm.
Thêm hàm sau vào main.py
để liệt kê bài nộp của học viên:
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
Sau đó, hãy cập nhật và chạy main.py
để xem điểm bài nộp.
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
và assignedRubricGrades
chứa:
criterionId
của tiêu chí chấm điểm tương ứng.points
mà giáo viên chỉ định cho từng tiêu chí. Điều này có thể là do cấp độ đã chọn, nhưng giáo viên cũng có thể đã ghi đè cấp độ này.levelId
của cấp được chọn cho mỗi tiêu chí. Nếu giáo viên không chọn cấp độ nhưng vẫn chỉ định điểm cho tiêu chí, thì trường này sẽ không xuất hiện.
Các danh sách này chỉ chứa các mục nhập cho tiêu chí mà giáo viên đã chọn một cấp hoặc đặt điểm. Ví dụ: nếu giáo viên chọn chỉ tương tác với một tiêu chí trong quá trình chấm điểm, thì draftRubricGrades
và assignedRubricGrades
sẽ chỉ có một mục, ngay cả khi tiêu chí có nhiều tiêu chí.
Xoá tiêu chí chấm điểm
Bạn có thể xoá một thang điểm bằng yêu cầu delete()
thông thường. Đoạn mã sau đây cho thấy một hàm mẫu để hoàn chỉnh, nhưng vì quá trình chấm điểm đã bắt đầu, nên bạn không thể xoá tiêu chí chấm điểm hiện tại:
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
Xuất và nhập tiêu chí chấm điểm
Giáo viên có thể xuất tiêu chí chấm điểm sang Google Trang tính theo cách thủ công để sử dụng lại.
Ngoài việc chỉ định tiêu chí chấm điểm trong mã, bạn có thể tạo và cập nhật tiêu chí chấm điểm từ các trang tính đã xuất này bằng cách chỉ định sourceSpreadsheetId
trong phần nội dung tiêu chí chấm điểm thay vì 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