Следующая версия
|
Предыдущая версия
|
tech:toloka [2022/03/22 05:59] dmitry_kalashnikov создано |
tech:toloka [2025/03/03 15:46] (текущий) anastasia_melnikova |
====== Тестирование диктанта в Яндекс.Толоке ====== | ====== Яндекс.Задания — тестирование диктанта ====== |
| |
===== Вводные ===== | ===== Вводные ===== |
| |
| |
**Цель**: получение текстов разнообразных вариантов написания диктанта для построения тепловой карты ошибок с последующим анализом возможных ошибок/вариантов и корректировки разметки. | **Цель**: получение текстов разнообразных вариантов написания диктанта для построения [[dictations/statistics/heatmap|тепловой карты ошибок]] с последующим анализом возможных ошибок/вариантов и корректировки разметки. |
| |
**Ограничение**: цельный текст диктанта под секретом, нельзя его полностью показывать отдельному человеку. | **Ограничение**: цельный текст диктанта под секретом, нельзя его полностью показывать отдельному человеку. |
| |
**Решение**: предлагать пользователям сервиса "Яндекс.Толока" писать отдельные предложения под диктовку, а затем склеивать результаты в единые тексты, затем формировать архив для импорта. | **Решение**: предлагать пользователям сервиса "Яндекс.Заданий" писать отдельные предложения под диктовку, а затем склеивать результаты в единые тексты, затем формировать [[tech/import|архив для импорта]]. |
| |
===== Описание решения ===== | ===== Описание решения ===== |
| |
Зарегистрируйтесь в сервисе | Зарегистрируйтесь в сервисе |
[[https://toloka.yandex.ru/|Яндекс.Толока]] в качестве заказчика. | [[https://tasks.yandex.ru//|Яндекс.Задания]] в качестве заказчика. |
| |
==== Пополнение баланса ==== | ==== Пополнение баланса ==== |
| |
Пополните баланс на нужную сумму (в долларах). Примерная экономика: 3 цента за предложение. В диктанте в среднем 15-20 предложений, следовательно, одно написание будет стоить от 45 до 60 центов. | Пополните баланс на нужную сумму (в рублях). Примерная экономика: 1,85 ₽ за предложение. В диктанте в среднем 15-20 предложений, следовательно, одно написание будет стоить от 28 до 37 рублей. |
| |
Можно пополнить баланс с расчётного счёта юрлица. | Можно пополнить баланс с расчётного счёта юрлица. |
==== Формирование проекта ==== | ==== Формирование проекта ==== |
| |
Создайте новый проект. | Создайте [[https://tasks.yandex.ru/requester/templates|новый проект]]. Шаблон: "Аудио → Расшифровка аудиозаписей". |
| |
**Название**: "Напишите предложение из школьного диктанта". | **Название для исполнителей**: "Напишите предложение из школьного диктанта". |
| |
**Описание для исполнителей**: "Нужно послушать и записать предложение со всеми знаками препинания, опираясь на собственную грамотность". | **Описание для исполнителей**: "Нужно послушать и записать предложение со всеми знаками препинания, опираясь на собственную грамотность". |
| |
**Интерфейс задания**: | **Интерфейс задания** → Конструктор шаблонов → Конфигурация: вставить json из поля ниже. |
| |
<code javascript json> | <code javascript json> |
**Инструкция для исполнителей** | **Инструкция для исполнителей** |
| |
| В поле "Инструкция для исполнителей" вставляется инструкция: |
<code> | <code> |
Используйте наушники для прослушивания аудиозаписи. | Используйте наушники для прослушивания аудиозаписи. |
* Предложение начинается с заглавной буквы. | * Предложение начинается с заглавной буквы. |
| |
Задание будет отклонено, если Ваш текст совсем не похож на продиктованный.'' | Задание будет отклонено, если Ваш текст совсем не похож на продиктованный. |
</code> | </code> |
| |
| После заполнения всех полей нажимается **Создать проект**. |
==== Создание пула ==== | ==== Создание пула ==== |
| |
Создаётся новый пул заданий, для каждого диктанта отдельный. Называние, например, "Диктант 1". | Создаётся новый пул заданий ("Добавить пул"), для каждого диктанта отдельный. Называние пишется в поле "Название пула (доступно только вам)", например, "Диктант 1" (название текущего диктанта). В публичное описание вставляется инструкция для исполнителей задания (например, //Внимательно послушайте и запишите предложение со всеми знаками препинания, опираясь только на собственную грамотность (без словарей, справочников и поисковиков)//). |
| |
Выставляется русский язык. Принимаются только исполнители, сдавшие тест на знание языка. | На странице пула выставляются следующие параметры: |
Выбирается, например, топ 50% лучших исполнителей. | * В поле **"Аудитория"** убирается галочка "В моих заданиях может содержаться шокирующий или порнографический контент", сохраняется опция "Языки" в поле "= Значение" выставляется "Русский". На шкале "Соотношение скорости и качества" выбирается, например, топ 60% лучших исполнителей. |
| {{:tech:audience.png?600|}} |
| |
Цена: $0,02 | * В поле **"Контроль качества"** удаляются поля "Учитывать последних страниц заданий... Минимальное время на страницу заданий", "Мнение большинства". Оставляется правило контроля качества **"Выполненные задания"**, там проставляются значения: ''Если отправленных страниц = 3, то приостановить в пуле навсегда'' — для того, чтобы один человек смог увидеть не более трёх предложений диктанта. В **"Причина"** вписывается "Ответ получен". |
| {{:tech:quality_control.png?600|}} |
| |
Контроль качества: перекрытие задания — ставится число написаний диктанта, которое нужно получить. Например, 100 написаний. | * В окне **"Цена"** в поле "Цена за страницу заданий, ₽" выставляется цена 1,85, в поле "Перекрытие" выставляется значение 120. |
Добавляется правило контроля качества: ''если отправленных страниц заданий = 3, то приостановить в пуле навсегда'' — для того, чтобы один человек смог увидеть не более трёх предложений диктанта. | {{:tech:price.png?400|}} |
| |
Тип пула: Пул с обычными заданиями. | * В расширенных настройках → Дополнительные настройки выбирается **"Время на страницу заданий, с"** — 600, **"Тип пула"** — Пул с обычными заданиями. Выбирается опция "Сохранять порядок заданий". |
| {{:tech:task-order.png?600|}} |
| |
Поставить галочку: сохранять порядок заданий. | ==== Клонирование пула ==== |
| Если в проекте есть пул, удовлетворяющий всем необходимым параметрам, его можно скопировать, чтобы не заполнять заново вручную все поля. Это можно сделать двумя способами: |
| - На странице проекта со всеми пулами заданий навести мышь на нужный и выбрать кнопку "Клонировать".// |
| {{:tech:clone_1.png?800|}}// |
| - На странице выбранного пула в дополнительных опциях по кнопке "…" выбрать "Клонировать".// |
| {{:tech:clone_02.png?800|}}// |
| |
==== Загрузка заданий ==== | ==== Загрузка заданий ==== |
| |
| Можно взять готовый [[https://docs.google.com/spreadsheets/d/1tVUvaM8ilou-GKqqeMVjZaqM2UWQnSynl0fpYWK9kuk/copy|шаблон]] или создать таблицу с нуля. |
| |
Формируется таблица в гугл.документах (https://sheet.new/) с двумя листами: | Формируется таблица в гугл.документах (https://sheet.new/) с двумя листами: |
* OUTPUT | * OUTPUT |
| |
На листе //INPUT// добавляется в ячейку A1 строка ''INPUT:audio''. Ниже вставляются ссылки на аудиофайлы предложений в прямом порядке. Ссылки можно получить в Учительской → Диктовка → Предложение → Скачать звуковой файл фрагмента. | На листе //INPUT// добавляется в ячейку A1 строка ''INPUT:audio''. |
| |
| Ниже вставляются ссылки на аудиофайлы предложений в прямом порядке. Ссылки на предложения можно получить в Учительской: страница диктанта → Страница диктовки → кнопка "Скачать" → "Скачать предложения". |
Примерно так должен выглядеть лист: | Примерно так должен выглядеть лист: |
| |
{{:tech:toloka_input.png|}} | {{:tech:toloka_input.png|}} |
| |
Далее, с листа копируется первый столбец и вставляется в текстовый файл. Каждая ссылка разделяется пустой строкой: | Далее с листа копируется первый столбец и вставляется в текстовый файл. Каждая ссылка разделяется пустой строкой: |
<code> | <code> |
INPUT:audio | INPUT:audio |
</code> | </code> |
| |
Файл сохраняется и загружается в текущий пул задач (кнопка "Загрузить"). Количество заданий на странице выбирается как "По пустой строке". | Файл сохраняется с расширением ''.tsv'' и загружается в текущий пул задач (кнопка **"Загрузить задания"**). |
==== Запуск пула ==== | ==== Запуск пула ==== |
| |
Разметка запускается и можно попить кофе, пока толокеры выполняют задания. | На странице пула нажимается кнопка **"Запустить разметку"**. |
| После модерации проект будет запущен и откроется исполнителям. |
| ==== Получение результатов написания ==== |
| |
==== Получение результатов ==== | После выполнения всех заданий можно скачать результаты по кнопке "Скачать результаты" в пуле. В окне скачивания выбираются только статусы "Принятые" и "ID Исполнителя". |
| |
По окончании разметки можно скачать результаты по одноимённой кнопке в пуле. В окне скачивания выбирается только статус "Принятые" без полей и разделения ответов пустой строкой. | {{:tech:results.png?400|}} |
| |
Данные из скачанного файла импортируются в таблицу, на лист //OUTPUT// так, чтобы в каждой строке была ссылка на аудиофайл и текст результата: | Данные из скачанного файла импортируются в таблицу, на лист //OUTPUT// так, чтобы в каждой строке была ссылка на аудиофайл, текст результата и ID толокера: |
| |
{{:tech:toloka_output.png|}} | {{:tech:toloka_output.png|}} |
| |
| ==== Анализ результатов написания ==== |
| |
| 1. Значения сортируются по столбцу с "ID толокера" (столбец "C").\\ |
| 2. Для всех недобросовестных толокеров, явно не старавшихся написать предложения, в столбце "D" пишется слово "бан" (для последующей фильтрации).\\ |
| 3. С помощью фильтра по значению "бан" (в столбце "D") копируются в новый лист с названием "BAN" все строки.\\ |
| 4. В листе "BAN" по столбцу "C" удаляются все повторы, чтобы в "ID толокеров" не осталось дублей.\\ |
| {{:tech:doubles.png?600|}}\\ |
| 5. Столбец с "ID толокеров" без первой строки сохраняется в новую таблицу типа ''ban.csv''.\\ |
| 6. На странице [[https://tasks.yandex.ru/requester/workers?ban=REQUESTER_BAN|Пользователи]] через "Загрузить файл" (1) загружается получившаяся csv-таблица. При загрузке списка пользователей нажимается "Добавить". На открывшейся странице с пользователями выбирается кнопка "Заблокировать" (2), место блокировки в открывшемся окне — "У меня".\\ |
| {{:tech:ban_01.jpg?350|}}\\ |
| {{:tech:ban_02.jpg?700|}}\\ |
| 7. В изначальном листе с помощью фильтра выбираются все строки //без// значения "бан", копируются и вставляются в новый лист с названием "OUTPUT". Старый лист удаляется.\\ |
| 8. Все строки сортируются по столбцу "B" ("Сортировать А > Я"), чтобы было проще убирать лишнее: удаляются пустые строки, обрывочные написания, незаконченные предложения (пропуск двух и более слов).\\ |
| |
| После анализа таблица готова для работы скрипта по формированию текстов диктанта. |
| ==== Подготовка скрипта слияния ==== |
| |
| В среде [[https://script.google.com/home|AppsScript]] создаётся новый проект (или можно запросить доступ к [[https://script.google.com/home/projects/1sb3IJs9TO9mGaAsjrr8hkKV1D1c7S8iYRUxDSPDRMJLxOVGQYF8Amlp_/edit|готовому проекту]]). Вставляется следующий код ниже. |
| |
| |
| <code javascript js> |
| //-------------------------------------------------------------------------------------------- |
| // ---=== основные параметры скрипта ===--- |
| // |
| // URL таблицы с данными по диктанту в нужном формате: два листа INPUT, OUTPUT. |
| // В первом упорядоченные ссылки на звуковые фрагменты по предложениям, во втором результаты из Толоки |
| const sheetName = 'https://docs.google.com/spreadsheets/d/1fbP4rylF5ryZS905D2xlgA9qhRimD6IxpHPR-bbz3tE/edit'; |
| // |
| // id директории, куда сохранять файлы диктантов (берётся из URL'а https://drive.google.com/drive/folders/%id) |
| const folderSave = '1s9p2RBowh3hou94p_jDdJ1Zv4Ty7fqu-'; |
| // |
| //id диктанта из Учительской (берётся из URL'а диктанта) |
| const dictId = '61f8e9a6a5fd104693b9646d'; |
| //-------------------------------------------------------------------------------------------- |
| |
| function RunImport() { |
| Logger.log("Запуск скрипта формирования текстов диктантов из результатов Яндекс.Толоки..."); //https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app |
| |
| |
| var sheetDict = SpreadsheetApp.openByUrl(sheetName); |
| Logger.log('Получен доступ к гугл.таблице "%s"', sheetDict.getName()); |
| var dictFolder = DriveApp.getFolderById(folderSave); |
| Logger.log('Получен доступ к директории "%s"', dictFolder.getName()); |
| |
| var range = sheetDict.getRange("INPUT!A2:A100"); //задаём название листа и интервал со значениями ссылок на диктовки предложений (задания в Толоке) |
| var sentencesIds = getSentenceIds(range.getValues()); |
| var range = sheetDict.getRange("OUTPUT!A2:B"); //задаём название листа и интервал со значениями результатов Толоки |
| mergeResults(range.getValues(), sentencesIds, dictFolder); |
| Logger.log("Готово!"); |
| }; |
| |
| function saveDict(text, dictFolder){ |
| var fileName = dictId + '_' + createUUID() + '.txt'; |
| dictFolder.createFile(fileName, text); |
| Logger.log('диктант "%s" сохранён (размер %d символов)', fileName, text.length); |
| } |
| |
| function mergeResults(valuesInput, sentencesIds, dictFolder){ |
| var dictText = []; |
| var link = ''; |
| var text = ''; |
| var idx = -1; |
| |
| for (var i = 0,countLines = valuesInput.length; i < countLines; i++) { |
| link = valuesInput[i][0].trim(); |
| text = valuesInput[i][1].trim(); |
| |
| if (link.length > 2 && text.length > 2) { |
| idx = sentencesIds.indexOf(link); |
| if (idx == -1) { |
| Logger.log('В таблице предложений не найден элемент со ссылкой %s', link) |
| } else { |
| if (dictText[idx] == null) { |
| dictText[idx] = text; |
| valuesInput[i][0] = '?'; |
| valuesInput[i][1] = '?'; |
| if (Object.keys(dictText).length == sentencesIds.length) |
| { |
| var fullText = dictText.join(" "); |
| saveDict(fullText, dictFolder); |
| dictText.length = 0; |
| i = 0; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // получение массива id предложений по ссылкам на аудиозаписи |
| function getSentenceIds(valuesInput){ |
| |
| var sentencesIds = []; |
| for (var i = 0,countLines = valuesInput.length; i < countLines; i++) { |
| if (valuesInput[i][0].length > 1) { |
| sentencesIds.push(valuesInput[i][0].trim()) |
| } |
| } |
| return (sentencesIds) |
| } |
| |
| function createUUID() { |
| // http://www.ietf.org/rfc/rfc4122.txt |
| var s = []; |
| var hexDigits = "0123456789abcdef"; |
| for (var i = 0; i < 36; i++) { |
| s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); |
| } |
| s[14] = "4"; |
| s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); |
| //s[8] = s[13] = s[18] = s[23] = "-"; |
| |
| var uuid = s.join(""); |
| return uuid; |
| } |
| </code> |
| |
| В начале, в секции "основные параметры скрипта", прописываются нужные значения: ID таблицы с результатами, ID папки для сохранения текстовых файлов, ID диктанта. Подробные пояснения в комментариях скрипта. |
| |
| После заполнения нужных параметров нажимается команда "Выполнить". |
| |
| ==== Получение архива с текстами диктантов ==== |
| |
| Через некоторое время появляются результаты в указанной папке на Гугл.Диске. Внутри папки выделяются все файлы и через контекстное меню скачивается архив: |
| |
| {{:tech:toloka_download.png?400|}} |
| |
| Архив импортируется в Учительскую в [[tech/import#format_importa_tekstov|формате для импорта]]. |
| |
| ==== Анализ вариантов без тепловой карты ==== |
| |
| Чтобы посмотреть на частотное распределение написаний, нужно в лист OUTPUT таблицы с выгружаемыми данными в ячейку C2 (1) вставить формулу ''=QUERY(B2:B; "select B, count(B) where B is not null group by B order by count(B) desc"; 0)''. |
| |
| Первый параметр функции указывает на интервал. Если исходных предложений несколько, то указывается конкретный для нужного предложения интервал, например B2:B100. После вставки справа должна появиться статистика по вариантам написания (2). |
| |
| {{:tech:example-without-map.png?800|}} |
| |
| Ссылка на [[https://docs.google.com/spreadsheets/d/1gzjjDJVhP0fHIigBSz4p1e20T4NYLslQ1KUGqYwwdZw/edit?gid=418681934#gid=418681934|таблицу из примера выше]]. |
| |
| ===== Сохранение артефактов ===== |
| |
| В комментарии к Редмайн-задаче даётся ссылка на гугл-таблицу, ссылка на "Карту ошибок", ссылка на проект в "Заданиях", прикрепляется zip-архив с текстами из Яндекс.Заданий. |