def update(db_conn, user, card, response): """ Update the card's parameters (and its parents') when given a response. """ # TODO-3 split up into smaller methods if not card.has_assessment(): return { 'response': Response({}), 'feedback': '', } errors = card.validate_response(response) if errors: return {'errors': errors} score, feedback = card.score_response(response) response = Response({ 'user_id': user['id'], 'card_id': card['entity_id'], 'unit_id': card['unit_id'], 'response': response, 'score': score, }) card_parameters = CardParameters.get(db_conn, entity_id=card['entity_id']) if not card_parameters: card_parameters = CardParameters({ 'entity_id': card['entity_id'] }) previous_response = Response.get_latest(db_conn, user_id=user['id'], unit_id=card['unit_id']) now = time() time_delta = now - (int(previous_response['created'].strftime("%s")) if previous_response else now) learned = (previous_response['learned'] if previous_response else init_learned) guess_distribution = card_parameters.get_distribution('guess') slip_distribution = card_parameters.get_distribution('slip') updates = formula_update(score, time_delta, learned, guess_distribution, slip_distribution) response['learned'] = updates['learned'] response, errors = response.save(db_conn) if errors: return {'errors': errors, 'feedback': feedback} card_parameters.set_distribution('guess', updates['guess_distribution']) card_parameters.set_distribution('slip', updates['slip_distribution']) card_parameters, errors = card_parameters.save(db_conn) if errors: return {'errors': errors, 'feedback': feedback} return {'response': response, 'feedback': feedback}
def get_card_route(request, card_id): """ Get a specific card given an ID. Show all relevant data, but not used for the learning interface. """ card = get_card_by_kind(card_id) if not card: return abort(404) unit = Unit.get_latest_accepted(entity_id=card['unit_id']) if not unit: return abort(404) # TODO-2 SPLITUP create new endpoints for these instead topics = Topic.list_by_entity_id(entity_id=card_id) versions = Card.get_versions(entity_id=card_id) requires = Card.list_requires(entity_id=card_id) required_by = Card.list_required_by(entity_id=card_id) params = CardParameters.get(entity_id=card_id) return 200, { 'card': card.deliver(access='view'), 'card_parameters': params.get_values(), 'unit': unit.deliver(), 'topics': [topic.deliver() for topic in topics], 'versions': [version.deliver() for version in versions], 'requires': [require.deliver() for require in requires], 'required_by': [require.deliver() for require in required_by], }
def choose_card(user, unit): """ Given a user and a unit, choose an appropriate card. Return a card instance. """ # TODO-3 simplify this method unit_id = unit['entity_id'] query = (Card.start_accepted_query() .filter({'unit_id': unit_id}) .sample(10)) # TODO-2 index # TODO-3 does this belong as a model method? # TODO-2 is the sample value decent? # TODO-2 has the learner seen this card recently? cards = [Card(d) for d in query.run(database.db_conn)] if not len(cards): return None previous_response = Response.get_latest(user_id=user['id'], unit_id=unit_id) if previous_response: learned = previous_response['learned'] # Don't allow the previous card as the next card cards = [ card for card in cards if card['entity_id'] != previous_response['card_id'] ] else: learned = init_learned shuffle(cards) assessment, nonassessment = partition(cards, lambda c: c.has_assessment()) choose_assessment = random() < p_assessment_map[floor(learned * 10)] if choose_assessment: if not len(assessment): return nonassessment[0] for card in assessment: params = CardParameters.get(entity_id=card['entity_id']) guess = params.get_distribution('guess').get_value() slip = params.get_distribution('slip').get_value() correct = calculate_correct(guess, slip, learned) if 0.25 < correct < 0.75: return card return assessment[0] if len(nonassessment): return nonassessment[0] if len(assessment): return assessment[0] return None
def update(user, card, response): """ Update the card's parameters (and its parents') when given a response. """ # TODO-3 split up into smaller methods if not card.has_assessment(): return { 'response': Response({}), 'feedback': '', } errors = card.validate_response(response) if errors: return {'errors': errors} score, feedback = card.score_response(response) response = Response({ 'user_id': user['id'], 'card_id': card['entity_id'], 'unit_id': card['unit_id'], 'response': response, 'score': score, }) card_parameters = CardParameters.get(entity_id=card['entity_id']) previous_response = Response.get_latest(user_id=user['id'], unit_id=card['unit_id']) now = time() time_delta = now - (int(previous_response['created'].strftime("%s")) if previous_response else now) learned = (previous_response['learned'] if previous_response else init_learned) guess_distribution = card_parameters.get_distribution('guess') slip_distribution = card_parameters.get_distribution('slip') updates = formula_update(score, time_delta, learned, guess_distribution, slip_distribution) response['learned'] = updates['learned'] response, errors = response.save() if errors: return {'errors': errors, 'feedback': feedback} card_parameters.set_distribution('guess', updates['guess_distribution']) card_parameters.set_distribution('slip', updates['slip_distribution']) card_parameters, errors = card_parameters.save() if errors: return {'errors': errors, 'feedback': feedback} return {'response': response, 'feedback': feedback}