rubric
— это шаблон, который учителя могут использовать при оценке работ учащихся. API Класса позволяет вам действовать от имени преподавателя и управлять этими критериями.
Рисунок 1. Вид образца рубрики задания в классе.
В этом руководстве объясняются основные концепции и функциональные возможности Rubrics API. Прочтите эти статьи Справочного центра, чтобы узнать об общей структуре критерия и о том, как оценивается критерий в пользовательском интерфейсе Класса.
Предварительные условия
В этом руководстве предполагается, что у вас есть следующее:
- Python 3.8.6 или новее
- Инструмент управления пакетами pip
- Проект Google Cloud .
- Аккаунт Google Workspace for Education с включенным Google Classroom .
- Тестовый класс с хотя бы одной учетной записью тестового учащегося. Если у вас нет класса Classroom, который можно использовать для тестирования, создайте его в пользовательском интерфейсе и добавьте учащегося-тестировщика .
Авторизация учетных данных для настольного приложения
Чтобы пройти аутентификацию в качестве конечного пользователя и получить доступ к пользовательским данным в вашем приложении, вам необходимо создать один или несколько идентификаторов клиента OAuth 2.0. Идентификатор клиента используется для идентификации одного приложения на серверах Google OAuth. Если ваше приложение работает на нескольких платформах, вам необходимо создать отдельный идентификатор клиента для каждой платформы.
- Перейдите на страницу учетных данных Google Cloud в консоли Google Cloud.
- Нажмите «Создать учетные данные» > «Идентификатор клиента OAuth» .
- Нажмите Тип приложения > Приложение для ПК .
- В поле Имя введите имя учетных данных. Это имя отображается только в консоли Google Cloud. Например, «Клиент предварительного просмотра рубрик».
- Нажмите Создать . Появится экран создания клиента OAuth, показывающий ваш новый идентификатор клиента и секрет клиента.
- Нажмите «Загрузить JSON» , а затем «ОК» . Вновь созданные учетные данные появятся в разделе «Идентификаторы клиентов OAuth 2.0».
- Сохраните загруженный файл JSON как
credentials.json
и переместите его в свой рабочий каталог. - Нажмите «Создать учетные данные» > «Ключ API» и запишите ключ API.
Дополнительные сведения см. в разделе Создание учетных данных доступа .
Настройка областей 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
областей авторизации . Вы можете увидеть все области действия Класса в областях OAuth 2.0 для Google API . Рубрики здесь не упоминаются, поскольку API все еще находится в предварительной версии.
Настройте образец
В своем рабочем каталоге установите клиентскую библиотеку Google для Python:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
Создайте файл с именем main.py
, который создаст клиентскую библиотеку и авторизует пользователя, используя ваш ключ API вместо 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
в классе.
Рисунок 2. Вид примера задания в Классе.
Создать рубрику
Теперь вы готовы начать управлять рубриками.
Рубрику можно создать в CourseWork
с помощью вызова Create
содержащего полный объект рубрики, в котором свойства ID для критериев и уровней опущены (они генерируются при создании).
Добавьте следующую функцию в 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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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)
rubric = create_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
print(json.dumps(rubric, indent=4))
Некоторые моменты по представлению рубрики:
- Порядок критериев и уровней отражен в пользовательском интерфейсе Класса.
- Уровни с очками (со свойством
points
) должны быть отсортированы по очкам либо в порядке возрастания, либо в порядке убывания (они не могут быть упорядочены случайным образом). - Учителя могут повторно сортировать критерии и уровни оценок (но не неоцененные уровни) в пользовательском интерфейсе, что изменяет их порядок в данных.
Дополнительные предостережения относительно структуры рубрик см. в ограничениях .
Вернувшись в пользовательский интерфейс, вы должны увидеть рубрику задания.
Рисунок 3. Вид образца рубрики задания в классе.
Читать рубрику
Рубрики можно читать стандартными методами 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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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',
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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)
# 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))
Теперь изменения должны быть отражены для преподавателя в Классе.
Рисунок 4. Вид обновленной рубрики.
Просмотр материалов, оцененных по рубрикам
На данный момент работы учащихся не могут оцениваться по критериям с помощью API, но вы можете прочитать оценки по критериям для работ, которые были оценены по критериям в пользовательском интерфейсе Класса.
Будучи учащимся в пользовательском интерфейсе Класса, выполните и сдайте образец задания . Затем в роли учителя вручную оцените задание, используя рубрику .
Рисунок 5. Представление учителя о рубрике во время выставления оценок.
Работы учащихся, оцененные по критерию, имеют два новых свойства: draftRubricGrades
и assignedRubricGrades
, представляющие баллы и уровни, выбранные учителем во время черновика и присвоенных состояний оценки соответственно.
Кроме того, работы учащихся со связанным критерием содержат поле rubricId
даже до выставления оценки. Это представляет последнюю рубрику, связанную с CourseWork
, и это значение может измениться, если преподаватели удалят и заново создадут рубрику.
Вы можете использовать существующие методы 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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).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,
# Specify the preview version. Rubrics CRUD capabilities are
# supported in V1_20231110_PREVIEW and later.
previewVersion="V1_20231110_PREVIEW"
).execute()
print(f"Rubric created with ID {rubric.get('id')}")
return rubric
except HttpError as error:
print(f"An error occurred: {error}")
return error
Обратная связь
Если вы обнаружите какие-либо проблемы или поделитесь своим мнением, поделитесь своим мнением .