Быстрый старт

Начинаем пользоваться

Импортируем клиент и создаем его инстанс, передав в него путь к конфигу, который мы записали ранее

Далее, начнем с его помощью выполнять различные действия на платформе

Инициализируем клиент

In[ ]:

from crowd_sdk.tagme import TagmeClientAdvanced

client = TagmeClientAdvanced("crowd.cfg")

Создаем свой проект, используя SDK

Для этого воспользуемся методом create_project

In[ ]:

from IPython.display import Markdown as md

project = await client.create_project(
    name="Имя вашего проекта",
    description="Описание вашего проекта",
    inner_comment="Внутренний комментарий для заказчика",
)

project_link = await client.gen_project_url(project.uid, project.organization_id)
md(f'**[cсылка на ваш проект]({project_link})**')

Out[ ]:

Добавляем инструкцию и интерфейс

У каждого проекта на TagMe есть методика. Она состоит из нескольких частей:

  • marker_brief - инструкция для разметчиков, сверстанная в HTML

  • forms - части интерфейса и различные настройки проекта

Форма проекта, в свою очередь, состоит из следующих полей:

  • html, css, js - интерфейс заданий проекта

  • config, specifications - различные настройки проекта в формате JSON

  • example - пример данных задания для показа в предпросмотре интерфейса

In[ ]:

# Добавим руками
marker_brief = """
Инструкция в формате HTML
"""

html = """
Интерфейс проекта (часть с HTML)
"""

css = """
Интерфейс проекта (часть с CSS)
"""

js = """
Интерфейс проекта (часть с JS)
"""


# Или просто скачаем готовые примеры
import aiohttp

async def download_text(url: str) -> str:
    async with aiohttp.ClientSession() as session:
      resp = await session.get(url)
      return await resp.text()

marker_brief  = await download_text("https://obs.ru-moscow-1.hc.sbercloud.ru/d-tagme-public/public/crowd_sdk/example_data/example_brief.html")
html          = await download_text("https://obs.ru-moscow-1.hc.sbercloud.ru/d-tagme-public/public/crowd_sdk/example_data/example_html.html")
css           = await download_text("https://obs.ru-moscow-1.hc.sbercloud.ru/d-tagme-public/public/crowd_sdk/example_data/example_css.css")
js            = await download_text("https://obs.ru-moscow-1.hc.sbercloud.ru/d-tagme-public/public/crowd_sdk/example_data/example_js.js")


# Или скопируем из другого проекта
# old_project = await client.get_project("id проекта")
# await client.load_project_method(old_project)
# old_method = old_project.method

# marker_brief = old_method.marker_brief
# html = old_method.forms.html
# css = old_method.forms.css
# js = old_method.forms.js

# Раскомментируйте чтобы посмотреть инструкцию прямо в ноутбуке
# from IPython.display import HTML
# HTML(marker_brief)

In[ ]:

from crowd_sdk.tagme.types import MethodData, MethodForms

forms = MethodForms(
    html=html,
    css=css,
    js=js,
    example={"text": "текст"}
)

method = MethodData(
    uid=project.method_id,
    name="Название методики",
    forms=forms,
    marker_brief=marker_brief,
)

await client.update_method(method=method)
md(f'**[ссылка на интерфейс проекта]({project_link}/forms)**')

Out[ ]:

Добавляем задачу в проект

In[ ]:

from crowd_sdk.tagme.types import TaskDataRequest, TaskType

create_task_request = TaskDataRequest(
    project_id=project.uid,
    organization_id=project.organization_id,
    name="Имя вашей задачи",
    overlap=2,
    type=TaskType.PROD, # or TaskType.STUDY | TaskType.EXAM
    description="Описание задачи",
)

task = await client.create_task(create_task_request)

task_link = await client.gen_task_url(task.project_id, task.uid, task.organization_id)
md(f'**[ссылка на вашу задачу]({task_link})**')

Out[ ]:

Загружаем задания в задачу

В SDK существуют различные способы загрузить данные в задачу. Рассмотрим их:

  1. Таблицей - в каждой строке содержатся данные для конкретного задания, так что можно загрузить сразу много заданий. Столбцы со значениями входных полей называются INPUT:название поля. Например, INPUT:text. Для контрольных заданий столбец с ожидаемым результатом задания помечается как GOLDEN:название поля. Например, GOLDEN:result. Для добавления подсказок к заданию можно добавить столбец вида HINT:название поля. Метод клиента для загрузки таблицы с данными называется upload_table и он обрабатывает форматы xls(x) и csv. Кроме того, есть метод upload_tsv_data, который позволяет загружать задания в формате tsv.

  2. Файлами - можно загрузить отдельные файлы, в которых лежат задания, подходящие под ваш интерфейс. Для этого существуют такие методы, как upload_files, upload_folder, upload_folder_to_task, upload_folders_to_task, upload_folders_to_task_and_start. По названиям методов можно понять, что они делают. Отличие upload_folder и upload_folder_to_task заключается в том, что в первый передается объект типа TaskData, а во второй - id задачи, так что скорее всего вам пригодится второй из них.

  3. Загрузка PDF - для этого есть метод upload_folder_pdf. Этот метод перед загрузкой преобразует pdf-файлы в png-изображения. Такие данные можно будет использовать для шаблона ``Сегментация PDF''.

  4. Загрузка списка заданий в формате JSON - для этого есть метод upload_json_data. Он принимает список объектов в формате JSON. Для каждого задания можно добавить предразметку, правильный ответ и подсказки.

Подробнее о форматах смотрите по ссылке.

Скачиваем данные

In[ ]:

import pandas as pd

session = aiohttp.ClientSession()
data = await (await session.get("https://obs.ru-moscow-1.hc.sbercloud.ru/d-tagme-public/public/crowd_sdk/example_data/example_data.xlsx")).content.read()
await session.close()

data_df = pd.read_excel(data)
data_df.head(5)

Out[ ]:

<ipython-input-10-597d07fd1ad6>:7: FutureWarning: Passing bytes to 'read_excel' is deprecated and will be removed in a future version. To read from a byte string, wrap it in a BytesIO object. data_df = pd.read_excel(data)

INPUT:text GOLDEN:music

0

седьмой б

artist

1

сбер поставь niletto

artist

2

включи песню звери

NaN

3

включи песню симбочка

NaN

4

владимир дормидонтов

NaN

Загружаем в задачу

In[ ]:

with open("data.xlsx", "wb") as f:
    f.write(data)

await client.upload_table(task.uid, "data.xlsx")

Добавляем разметчиков в проект

Создаем группу разметчиков и добавляем в нее себя

In[ ]:

self_person = await client.get_self_person()
markers = [self_person.uid]
pool = await client.create_pool(
    markers=markers,
    name="Имя вашей группы разметчиков",
)

Добавляем группу разметчиков в проект

Добавляем еще разметчиков

Если прямо сейчас вы присутствуете на офлайн-обучении в СберУниверситете, вам доступна группа разметчиков, которую мы добавили специально для обучения. Давайте добавим и ее.

In[ ]:

await client.add_users_to_project(project_id=project.uid, pool_id=pool.uid)

Добавляем группу разметчиков в наш проект

In[ ]:

# await client.add_users_to_project(project.uid, pool.uid)

Запускаем задачу

In[ ]:

await client.start_task(task.uid)
print("Task started")

Out[ ]:

Task started

Ожидаем завершение разметки задачи

Если вы присутствуете на обучении, наши разметчики скоро разметят ваше задание. В ином случае, вам предлагается зайти на платформу как разметчик и разметить вашу задачу самому.

Получаем результаты разметки

Получаем сырые результаты

Чтобы получить результаты разметки, используя SDK, у клиента есть такие методы, как get_task_assignments и get_task_assignments_df. Первый из них возвращает список объектов типа Assignment, а второй, как можно догадаться, возвращает DataFrame, который содержит в себе таблицу с результатами.

Чаще всего, при работе внутри блокнотов удобнее пользоваться DataFrame-ами, так что давайте и сейчас им воспользуемся.

In[ ]:

df = await client.get_task_assignments_df(task.uid)
df.head(5)

Out[ ]:

OUTPUT:Comment OUTPUT:correct accepted_at assignment_id enabled end_date file_name item_id item_type marker_id organization_id person_id start_date status submitted_at task_id

0

1

2024-07-30 17:46:55.350004

04f9dbd8-a86f-4bf2-8739-7edb232ab6b1

True

2024-07-30 17:46:55.350004

data_11.json

890b6c51-dc96-4f32-9378-1ec83eaef14c

data

f17e770b-5344-49b7-8bb4-f7d44c539e66

d9d24126-e268-4a7e-bb83-8ee9123e0ef7

f17e770b-5344-49b7-8bb4-f7d44c539e66

2024-07-30 17:43:18.566430

ACCEPTED

2024-07-30 17:46:55.350004

92f16cf4-79f8-44b5-918e-428186fa3e93

1

2

2024-07-30 17:46:56.319992

42e34a34-15d7-4c0f-a46c-553135d164a7

True

2024-07-30 17:46:56.319992

data_19.json

c1a5ba10-f1d7-4cf6-9118-9d0eb88aa7f5

data

f17e770b-5344-49b7-8bb4-f7d44c539e66

d9d24126-e268-4a7e-bb83-8ee9123e0ef7

f17e770b-5344-49b7-8bb4-f7d44c539e66

2024-07-30 17:46:55.403594

ACCEPTED

2024-07-30 17:46:56.319992

92f16cf4-79f8-44b5-918e-428186fa3e93

2

3

2024-07-30 17:46:57.163482

8c9b91c2-e3b5-4431-8418-00cbe9fe0787

True

2024-07-30 17:46:57.163482

data_21.json

b8136362-bac2-4b72-903c-5c743bf6911c

data

f17e770b-5344-49b7-8bb4-f7d44c539e66

d9d24126-e268-4a7e-bb83-8ee9123e0ef7

f17e770b-5344-49b7-8bb4-f7d44c539e66

2024-07-30 17:46:56.367860

ACCEPTED

2024-07-30 17:46:57.163482

92f16cf4-79f8-44b5-918e-428186fa3e93

3

4

2024-07-30 17:46:58.452109

4f14d70a-f6aa-4dca-9440-56c6f582e24e

True

2024-07-30 17:46:58.452109

data_5.json

ab225d84-45e3-425e-89dd-a9cb6b519cc1

data

f17e770b-5344-49b7-8bb4-f7d44c539e66

d9d24126-e268-4a7e-bb83-8ee9123e0ef7

f17e770b-5344-49b7-8bb4-f7d44c539e66

2024-07-30 17:46:57.207142

ACCEPTED

2024-07-30 17:46:58.452109

92f16cf4-79f8-44b5-918e-428186fa3e93

4

1

2024-07-30 17:46:59.630209

91327f8a-379a-4576-96ee-5439613e8ae0

True

2024-07-30 17:46:59.630209

data_20.json

fde0f063-efb3-403a-94a3-b8abf48bcb2d

data

f17e770b-5344-49b7-8bb4-f7d44c539e66

d9d24126-e268-4a7e-bb83-8ee9123e0ef7

f17e770b-5344-49b7-8bb4-f7d44c539e66

2024-07-30 17:46:58.493102

ACCEPTED

2024-07-30 17:46:59.630209

92f16cf4-79f8-44b5-918e-428186fa3e93

Для сравнения посмотрим, как выглядит один ответ разметчика при использовании get_task_assignments (для удобства конвертируем в json)

In[ ]:

from crowd_sdk.core.utils.common import dataclass_to_dict

assignments = await client.get_task_assignments(task_id=task.uid)
first_assignment = assignments[0]
dataclass_to_dict(first_assignment)

Out[ ]:

{'file_name': 'data_11.json', 'item_id': '890b6c51-dc96-4f32-9378-1ec83eaef14c', 'marker_id': 'f17e770b-5344-49b7-8bb4-f7d44c539e66', 'organization_id': 'd9d24126-e268-4a7e-bb83-8ee9123e0ef7', 'person_id': 'f17e770b-5344-49b7-8bb4-f7d44c539e66', 'price': 0.0, 'result': {'Comment': '', 'correct': 1}, 'status': 'ACCEPTED', 'task_id': '92f16cf4-79f8-44b5-918e-428186fa3e93', 'start_date': '2024-07-30T17:43:18.566430+03:00', 'end_date': '2024-07-30T17:46:55.350004+03:00', 'submitted_at': '2024-07-30T17:46:55.350004+03:00', 'accepted_at': '2024-07-30T17:46:55.350004+03:00', 'item_type': 'data', 'assignment_id': '04f9dbd8-a86f-4bf2-8739-7edb232ab6b1', 'enabled': True}

Что в таблице, что в объектах, которые возвращаются из get_task_assignments, содержится различная информация об ответах разметчиков.

Главное различие, которое можно заметить, заключается в том, что при выгрузке таблицей, поле result разбивается на ключи словаря, и они становятся разными столбцами с названием OUTPUT:название поля.