def exercise(exercise_question, exercise_data, channel): args_data = get_content_node_args(exercise_data) contentnode_kwargs = get_content_node_kwargs(exercise_data) del contentnode_kwargs['extra_fields'] mastery_model_dict = contentnode_kwargs['exercise_data'] exercise = ExerciseNode(*args_data, **contentnode_kwargs) exercise.add_question(exercise_question) channel.add_child(exercise) exercise_data['questions'] = [exercise_question] exercise_data['extra_fields'] = mastery_model_dict del exercise_data['exercise_data'] return exercise
def get_file(name, directory, filename, title=None): filepath = os.path.join(directory, filename) if title is None: title = name source_id = "{}/{}".format(name, filename) node = None if filename.endswith(".pdf"): node = DocumentNode( title=title, description="Documentación de {}".format(name), source_id=source_id, license=AIEP_License, language="es", files=[DocumentFile( path=filepath, language="es", )], ) elif filename.endswith("h5p"): mp4_file = get_video_from_h5p(filepath) if mp4_file is None: classNode = H5PAppNode classFile = H5PFile else: classNode = VideoNode classFile = VideoFile filepath = mp4_file node = classNode( title=get_title_from_video(title, filename), description="Vídeo explicativo de la {}".format(name), source_id=source_id, license=AIEP_License, language="es", files=[classFile( path=filepath, language="es", )], ) elif filename.endswith("xls"): node = ExerciseNode( source_id=source_id, title="Ejercicios de {}".format(name), author="Equipo de AIEP", description="Preguntas de la unidad 1", language="es", license=AIEP_License, thumbnail=None, exercise_data={ "mastery_model": exercises.M_OF_N, # \ "m": 2, # learners must get 2/3 questions correct to complete "n": 3, # / "randomize": True, # show questions in random order }, questions=leer_preguntas(filepath), ) return node
def create_node(node, assessment_dict, subtitle_path, vtt_videos, base_path, lite_version, lang_code): kind = node.get('kind') # Exercise node creation if kind == 'Exercise': child_node = ExerciseNode( source_id=node['id'], title=node['title'], exercise_data={ 'mastery_model': node.get('suggested_completion_criteria') }, description='' if node.get("description") is None else node.get( "description", '')[:400], license=licenses.ALL_RIGHTS_RESERVED, thumbnail=node.get('image_url_256'), ) # build exercise urls for previews full_path = base_path + node.get('path').strip('khan') slug = full_path.split('/')[-2] full_path = full_path.replace(slug, 'e') + slug # attach Perseus questions to Exercises for item in node['all_assessment_items']: # we replace all references to assessment images with the local file path to the image for match in re.finditer(FILE_URL_REGEX, assessment_dict[item['id']]["item_data"]): file_path = str(match.group(0)).replace('\\', '') file_path = file_path.replace(REPLACE_STRING, IMAGE_DL_LOCATION) assessment_dict[item['id']]["item_data"] = re.sub( FILE_URL_REGEX, file_path, assessment_dict[item['id']]["item_data"], 1) question = PerseusQuestion( id=item['id'], raw_data=assessment_dict[item['id']]['item_data'], source_url=full_path if not lite_version else None, ) child_node.add_question(question) # Topic node creation elif kind == 'Topic': child_node = TopicNode( source_id=node["id"], title=node["title"], description='' if node.get("description") is None else node.get( "description", '')[:400]) # Video node creation elif kind == 'Video': # standard download url for KA videos download_url = "https://cdn.kastatic.org/KA-youtube-converted/{0}.mp4/{1}.mp4".format( node['youtube_id'], node['youtube_id']) files = [VideoFile(download_url)] if node['youtube_id'] in vtt_videos: files.append( SubtitleFile(subtitle_path + '/{}.vtt'.format(node['youtube_id']), language=getlang(lang_code))) child_node = VideoNode( source_id=node["id"], title=node["title"], description='' if node.get("description") is None else node.get( "description", '')[:400], files=files, thumbnail=node.get('image_url'), license=licenses.CC_BY_NC_SA) else: # unknown content file format return None return child_node
def create_exercise_nodes(self, channel): """ This function adds a few exercise nodes to the channel content tree. TODO: handle exercises with embedded image links + base64 encoded data. """ # EXERCISES exercices_folder = TopicNode( source_id='uniqid011', title='Exercise Nodes', description='Put folder description here', author=None, language=getlang('en').id, thumbnail=None, ) channel.add_child(exercices_folder) exercise1 = ExerciseNode( source_id='uniqid012', title='Basic questions', author='LE content team', description= 'Showcase of the simple exercises supported by Ricecooker and Studio', language=getlang('en').id, license=get_license(licenses.CC_BY, copyright_holder='Copyright holder name'), thumbnail=None, exercise_data={ 'mastery_model': exercises.M_OF_N, # or exercises.DO_ALL 'randomize': True, 'm': 2, 'n': 3, }, questions=[ MultipleSelectQuestion( id='ex2aQ1', question= "Which numbers are even?\n\nTest local image include: ![](content/ricecooker-channel-files/html5_vuejs.jpg)", correct_answers=[ "2", "4", ], all_answers=["1", "2", "3", "4", "5"], hints=[ "There are two answers.", "Both answers are multiples of two." ]), SingleSelectQuestion( id='ex2aQ2', question="What is 2 times 3?", correct_answer="6", all_answers=["2", "3", "5", "6"], ), InputQuestion( id='ex2aQ3', question="Name a factor of 10.", answers=["1", "2", "5", "10"], ) ]) exercices_folder.add_child(exercise1) # LOAD JSON DATA (as string) FOR PERSEUS QUESTIONS SAMPLE_PERSEUS_4_JSON = open( './content/ricecooker-channel-files/perseus_graph_question.json', 'r').read() exercise2 = ExerciseNode( source_id='baszzzs1', title='Perseus questions', author='LE content team', description='An example exercise with Persus questions', language=getlang('en').id, license=get_license(licenses.CC_BY, copyright_holder='Copyright holder name'), thumbnail=None, exercise_data={ 'mastery_model': exercises.M_OF_N, # or exercises.DO_ALL 'randomize': True, 'm': 1, 'n': 1, }, questions=[ PerseusQuestion( id='ex2bQ4', raw_data=SAMPLE_PERSEUS_4_JSON, source_url= 'https://github.com/learningequality/sample-channels/blob/master/contentnodes/exercise/sample_perseus04.json' ), ]) exercices_folder.add_child(exercise2)
def add_lesson_practice(self, lesson, url, title, course_title, module_title): LOGGER.info("Adding practice for the course {}...".format( lesson.title)) # resp = downloader.make_request(url, cookies=self.cookies).content.decode("utf-8") file_path = "files/{}/{}/{}/{}-practice.txt".format( course_title, module_title, lesson.title, title) with open(file_path, "r") as resp: page = BeautifulSoup(resp, "html.parser") # Get the question description question_paras = page.find( "div", class_="activity-intro__question").find_all("p") question_description = "" for description in question_paras: question_description = question_description + description.text + "\n" # Get the practice data to parse pattern = re.compile("window.lessonData = (.*;)") lesson_data = json.loads( pattern.search(page.text).group(1).replace(";", "")) practice_data = lesson_data["activities"][0]["activity"] practice_type = lesson_data["activities"][0]["type"] questions_add_to_exercise = [] practice_id = "{}-practice".format(lesson.source_id) # A multiple select question if practice_type in [ "select-right", "switches-text", "strike-through", "tag-cloud" ]: questions_add_to_exercise.append( self.add_a_multiple_select_question( practice_data, question_description, practice_id)) # A single select question elif practice_type in [ "swipe-selector", "twitter-draganddrop", "image-slider" ]: questions_add_to_exercise.append( self.add_a_single_select_question(practice_data, question_description, practice_id)) # Multiple single select questions elif practice_type in ["text-drawer", "boolean-selector"]: questions_add_to_exercise = self.add_multiple_single_select_questions( practice_data["options"], question_description, practice_id) else: LOGGER.error("Type {} hasn't been analyzed: {}".format( practice_type, url)) return # Create exercise node exercise_id = "{} Practice".format(lesson.title) exercise = ExerciseNode( source_id=exercise_id, title=title, license=CC_BY_NC_SALicense( copyright_holder="Google Garage Digital"), language=CHANNEL_LANGUAGE, thumbnail=None, exercise_data={ "master_model": exercises.DO_ALL, "randomize": False, }, questions=questions_add_to_exercise, ) lesson.add_child(exercise)
def create_exercise_nodes(self, channel): """ This function adds a few exercise nodes to the channel content tree. TODO: handle exercises with embedded image links + base64 encoded data. """ # EXERCISES exercices_folder = TopicNode( source_id='mdmdmai3i13', title='Exercise Nodes', description='Put folder description here', author=None, language=getlang('en').id, thumbnail=None, ) channel.add_child(exercices_folder) exercise2a = ExerciseNode( source_id='asisis9', title='Basic questions', author='LE content team', description= 'Showcase of the simple exercises supported by Ricecooker and Studio', language=getlang('en').id, license=get_license(licenses.CC_BY, copyright_holder='Copyright holder name'), thumbnail=None, exercise_data={ 'mastery_model': exercises.M_OF_N, # or exercises.DO_ALL 'randomize': True, 'm': 2, 'n': 3, }, questions=[ MultipleSelectQuestion( id='ex2aQ1', question="Which numbers are even?", correct_answers=[ "2", "4", ], all_answers=["1", "2", "3", "4", "5"], # hints? ), SingleSelectQuestion( id='ex2aQ2', question="What is 2 times 3?", correct_answer="6", all_answers=["2", "3", "5", "6"], # hints? ), InputQuestion( id='ex2aQ3', question="Name a factor of 10.", answers=["1", "2", "5", "10"], # hints? ) ]) exercices_folder.add_child(exercise2a) # LOAD JSON DATA (as string) FOR PERSEUS QUESTIONS SAMPLE_PERSEUS_4_JSON = open( './content/ricecooker-channel-files/sample_perseus04.json', 'r').read() exercise2b = ExerciseNode( source_id='baszzzs1', title='Perseus questions', author='LE content team', description='An example exercise with Persus questions', language=getlang('en').id, license=get_license(licenses.CC_BY, copyright_holder='Copyright holder name'), thumbnail=None, exercise_data={ 'mastery_model': exercises.M_OF_N, # or exercises.DO_ALL 'randomize': True, 'm': 2, 'n': 3, }, questions=[ PerseusQuestion( id='ex2bQ4', raw_data=SAMPLE_PERSEUS_4_JSON, source_url= 'https://github.com/learningequality/sample-channels/blob/master/contentnodes/exercise/sample_perseus04.json' ), ]) exercices_folder.add_child(exercise2b) SAMPLE_PERSEUS_4_dhanam4_JSON = open( './content/ricecooker-channel-files/sample_perseus04dhanam4.json', 'r').read() exercise2b_dhanam4 = ExerciseNode( source_id='test_dhanam4', title='Perseus question by dhanam4', author='dhanam4', description='dhanam4\'s example exercise with Persus questions', language=getlang('en').id, license=get_license(licenses.CC_BY, copyright_holder='dhanam4'), thumbnail=None, exercise_data={ 'mastery_model': exercises.M_OF_N, # or exercises.DO_ALL 'randomize': True, 'm': 2, 'n': 3, }, questions=[ PerseusQuestion( id='test_ex2bQ4dhanam4', raw_data=SAMPLE_PERSEUS_4_dhanam4_JSON, source_url= 'doesnt matter what goes here.. used for information purposes only' ), ]) exercices_folder.add_child(exercise2b_dhanam4)