rubric
adalah template yang dapat digunakan pengajar saat menilai kiriman siswa. Classroom API memungkinkan Anda bertindak atas nama pengajar untuk mengelola rubrik ini, serta membaca nilai rubrik pada kiriman siswa.
Gambar 1. Tampilan contoh rubrik pada tugas Classroom.
Panduan ini menjelaskan konsep dan fungsi dasar Rubrics API. Lihat artikel Pusat Bantuan ini untuk mempelajari struktur umum rubrik dan cara penilaian rubrik dilakukan di UI Classroom.
Prasyarat
Panduan ini mengasumsikan bahwa Anda memiliki hal berikut:
- Python 3.8.6 atau yang lebih baru
- Alat pengelolaan paket pip
- Project Google Cloud.
- Akun Google Workspace for Education dengan Google Classroom diaktifkan dan lisensi Google Workspace for Education Plus yang ditetapkan untuk akun tersebut. Anda dapat meminta akun demo developer yang diupgrade jika Anda tidak memilikinya.
- Kelas pengujian dengan setidaknya satu akun siswa pengujian. Jika Anda tidak memiliki kelas Classroom yang dapat digunakan untuk pengujian, buat kelas di UI dan tambahkan siswa penguji.
Mengizinkan kredensial untuk aplikasi desktop
Untuk mengautentikasi sebagai pengguna akhir dan mengakses data pengguna di aplikasi Anda, Anda perlu membuat satu atau beberapa Client ID OAuth 2.0. Client ID digunakan untuk mengidentifikasi aplikasi tunggal ke server OAuth Google. Jika aplikasi Anda berjalan di beberapa platform, Anda harus membuat client ID terpisah untuk setiap platform.
- Buka halaman Kredensial Google Cloud di Konsol Google Cloud.
- Klik Create Credentials > OAuth client ID.
- Klik Jenis aplikasi > Aplikasi desktop.
- Di kolom Name, ketik nama untuk kredensial. Nama ini hanya ditampilkan di Konsol Google Cloud. Misalnya, "Rubrics client".
- Klik Buat. Layar klien OAuth yang dibuat akan muncul, menampilkan Client ID dan Rahasia klien baru Anda.
- Klik Download JSON, lalu OK. Kredensial yang baru dibuat akan muncul di bagian Client ID OAuth 2.0.
- Simpan file JSON yang didownload sebagai
credentials.json
, dan pindahkan file tersebut ke direktori kerja Anda. - Klik Create Credentials > API Key dan catat kunci API.
Lihat Membuat kredensial akses untuk mempelajari lebih lanjut.
Mengonfigurasi cakupan OAuth
Bergantung pada cakupan OAuth yang ada di project Anda, Anda mungkin perlu mengonfigurasi cakupan tambahan.
- Buka OAuth consent screen.
- Klik Edit Aplikasi > Simpan dan Lanjutkan untuk membuka layar Cakupan.
- Klik Tambahkan atau Hapus Cakupan.
- Tambahkan cakupan berikut jika Anda belum memilikinya:
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.courses
- Kemudian, Klik Perbarui > Simpan dan Lanjutkan > Simpan dan Lanjutkan > Kembali ke Dasbor.
Lihat Mengonfigurasi layar izin OAuth untuk mempelajari lebih lanjut.
Cakupan classroom.coursework.students
memungkinkan akses baca dan tulis ke
rubrik (bersama dengan akses ke CourseWork
), dan cakupan classroom.courses
memungkinkan pembacaan dan penulisan kursus.
Cakupan yang diperlukan untuk metode tertentu tercantum dalam dokumentasi referensi
untuk metode tersebut. Lihat cakupan otorisasi courses.courseWork.rubrics.create
sebagai contoh. Anda dapat melihat semua cakupan Classroom di Cakupan OAuth 2.0 untuk Google API.
Mengonfigurasi contoh
Di direktori kerja Anda, instal library klien Google untuk Python:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
Buat file bernama main.py
yang membangun library klien dan mengizinkan
pengguna, menggunakan kunci API Anda sebagai pengganti 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)
Jalankan skrip menggunakan python main.py
. Anda akan diminta untuk login dan menyetujui cakupan OAuth.
Membuat tugas
Rubrik dikaitkan dengan tugas, atau CourseWork
, dan hanya
bermakna dalam konteks CourseWork
tersebut. Rubrik hanya dapat dibuat oleh
project Google Cloud yang membuat item induk CourseWork
. Untuk
tujuan panduan ini, buat tugas CourseWork
baru dengan skrip.
Tambahkan kode berikut ke 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
Sekarang perbarui main.py
untuk mengambil course_id
class pengujian yang baru saja Anda buat, buat tugas contoh baru, dan ambil coursework_id
tugas:
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.
Simpan course_id
dan coursework_id
. ID ini diperlukan untuk semua operasi CRUD rubrik.
Sekarang Anda akan memiliki contoh CourseWork
di Classroom.
Gambar 2. Tampilan contoh tugas di Classroom.
Memeriksa kelayakan pengguna
Pembuatan dan pembaruan rubrik mengharuskan pengguna yang membuat permintaan dan pemilik kursus yang sesuai memiliki lisensi Google Workspace for Education Plus yang ditetapkan untuk mereka. Classroom mendukung endpoint kelayakan pengguna untuk memungkinkan developer menentukan kemampuan yang dapat diakses pengguna.
Perbarui dan jalankan main.py
untuk mengonfirmasi bahwa akun pengujian Anda memiliki akses ke kemampuan rubrik:
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.')
Membuat rubrik
Sekarang Anda siap untuk mulai mengelola rubrik.
Rubrik dapat dibuat di CourseWork
dengan panggilan create()
yang berisi
objek rubrik lengkap, dengan properti ID untuk kriteria dan tingkat
dihapus (properti ini dibuat saat pembuatan).
Tambahkan fungsi berikut ke 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
Kemudian, perbarui dan jalankan main.py
untuk membuat contoh rubrik, menggunakan ID Course
dan CourseWork
Anda dari sebelumnya:
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))
Beberapa poin tentang representasi rubrik:
- Urutan kriteria dan tingkat tercermin dalam UI Classroom.
- Level yang diberi skor (yang memiliki properti
points
), harus diurutkan berdasarkan poin dalam urutan menaik atau menurun (tidak dapat diurutkan secara acak). - Pengajar dapat mengurutkan ulang kriteria dan tingkat yang diberi skor (tetapi tidak untuk tingkat yang tidak diberi skor) di UI, dan hal itu mengubah urutannya dalam data.
Lihat batasan untuk mengetahui peringatan selengkapnya tentang struktur rubrik.
Kembali di UI, Anda akan melihat rubrik pada tugas.
Gambar 3. Tampilan contoh rubrik pada tugas Classroom.
Membaca rubrik
Rubrik dapat dibaca dengan metode list()
dan get()
standar.
Maksimal hanya ada satu rubrik dalam tugas, sehingga list()
mungkin tampak
tidak intuitif, tetapi berguna jika Anda belum memiliki ID rubrik. Jika tidak ada rubrik yang terkait dengan CourseWork
, respons list()
akan kosong.
Tambahkan fungsi berikut ke 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
Perbarui dan jalankan main.py
untuk mengambil rubrik yang Anda tambahkan:
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.
Perhatikan properti id
dalam rubrik untuk langkah-langkah selanjutnya.
Get()
berfungsi dengan baik jika Anda memiliki ID rubrik. Penggunaan get()
dalam fungsi
sebagai gantinya mungkin terlihat seperti:
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
Implementasi ini menampilkan 404 jika tidak ada rubrik.
Memperbarui rubrik
Pembaruan pada rubrik dilakukan dengan panggilan patch()
. Karena struktur rubrik yang kompleks, pembaruan harus dilakukan dengan pola baca-ubah-tulis, dengan mengganti seluruh properti criteria
.
Aturan pembaruan adalah sebagai berikut:
- Kriteria atau tingkat yang ditambahkan tanpa ID dianggap sebagai penambahan.
- Kriteria atau level yang tidak ada dari sebelumnya dianggap sebagai penghapusan.
- Kriteria atau tingkat dengan ID yang ada tetapi data yang diubah dianggap sebagai pengeditan. Properti yang tidak diubah akan tetap seperti semula.
- Kriteria atau tingkat yang diberikan dengan ID baru atau tidak diketahui dianggap sebagai error.
- Urutan kriteria dan tingkat baru dianggap sebagai urutan UI baru (dengan batasan yang disebutkan di atas).
Tambahkan fungsi untuk memperbarui rubrik:
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
Dalam contoh ini, kolom criteria
ditentukan untuk dimodifikasi dengan
updateMask
.
Kemudian, ubah main.py
untuk membuat perubahan pada setiap aturan pembaruan yang disebutkan di atas:
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))
Perubahan kini akan terlihat oleh pengajar di Classroom.
Gambar 4. Tampilan rubrik yang diperbarui.
Melihat kiriman yang dinilai dengan rubrik
Untuk saat ini, kiriman tugas siswa tidak dapat diberi nilai dengan rubrik oleh API, tetapi Anda dapat membaca nilai rubrik untuk kiriman tugas yang telah diberi nilai dengan rubrik di UI Classroom.
Sebagai siswa di UI Classroom, selesaikan dan serahkan contoh tugas Anda. Kemudian, sebagai pengajar, nilai tugas secara manual menggunakan rubrik.
Gambar 5. Tampilan rubrik pengajar selama penilaian.
StudentSubmissions
yang telah dinilai dengan rubrik memiliki dua properti baru: draftRubricGrades
dan assignedRubricGrades
, yang masing-masing merepresentasikan poin dan tingkat yang dipilih oleh pengajar selama status penilaian draf dan tugas.
Anda dapat menggunakan metode studentSubmissions.get()
dan
studentSubmissions.list()
yang ada untuk melihat kiriman yang dinilai.
Tambahkan fungsi berikut ke main.py
untuk mencantumkan tugas siswa:
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
Kemudian, perbarui dan jalankan main.py
untuk melihat nilai kiriman.
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
dan assignedRubricGrades
berisi:
criterionId
dari kriteria rubrik yang sesuai.points
yang ditetapkan guru untuk setiap kriteria. Hal ini bisa berasal dari level yang dipilih, tetapi pengajar juga dapat menggantinya.levelId
tingkat yang dipilih untuk setiap kriteria. Jika pengajar tidak memilih level, tetapi tetap memberikan poin untuk kriteria, kolom ini tidak ada.
Daftar ini hanya berisi entri untuk kriteria yang tingkatnya dipilih atau poinnya ditetapkan oleh pengajar. Misalnya, jika pengajar memilih untuk hanya berinteraksi dengan satu kriteria selama penilaian, draftRubricGrades
dan assignedRubricGrades
hanya akan memiliki satu item, meskipun rubrik memiliki banyak kriteria.
Menghapus rubrik
Rubrik dapat dihapus dengan permintaan delete()
standar. Kode berikut
menampilkan contoh fungsi untuk kelengkapan, tetapi karena penilaian sudah
dimulai, Anda tidak dapat menghapus rubrik saat ini:
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
Mengekspor dan mengimpor rubrik
Rubrik dapat diekspor secara manual ke Google Spreadsheet untuk digunakan kembali oleh pengajar.
Selain menentukan kriteria rubrik dalam kode, Anda dapat membuat dan memperbarui rubrik dari spreadsheet yang diekspor ini dengan menentukan sourceSpreadsheetId
dalam isi rubrik, bukan 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