Skip to content

Commit

Permalink
feat: add support for user feedback on autogenerated transcripts (#33518
Browse files Browse the repository at this point in the history
)

* feat: WIP transcript feedback

* feat: Add UI mock for Transcript Feedbacks (#33416)

* feat: Add UI mock for Transcript Feedbacks

* fix: Fix mongo tests

* feat: Get video_uuid, user_uuid and language for request (#33445)

* feat: make call to ai-translations to obtain feedback

* feat: Show widget if transcript was AI generated

* feat: bind all class methods

* fix: async calls

* feat: send request when choosing feedback

* feat: update showing condition (#33474)

* fix: ajax success lint

* fix: video caption specs errors fixed

* feat: add coverage to feedback widget

* chore: connect XT to LMS and CMS

* feat: use url

* chore: add vars to devstack

* chore: fix url name

* feat: update unit tests regarding env vars

* fix: fix test_video_mongo

* feat: add more tests

* feat: remove console log

Co-authored-by: Jesper Hodge <[email protected]>

* fix: rename shouldShowWidget to loadAndSetVisibility

---------

Co-authored-by: María Guillermina Véscovo <[email protected]>
Co-authored-by: Jesper Hodge <[email protected]>
  • Loading branch information
3 people authored Nov 6, 2023
1 parent 2cf4d73 commit e51c01b
Show file tree
Hide file tree
Showing 20 changed files with 882 additions and 150 deletions.
3 changes: 3 additions & 0 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2655,6 +2655,9 @@
}
EDXAPP_PARSE_KEYS = {}

############################ AI_TRANSLATIONS ##################################
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'

###################### DEPRECATED URLS ##########################

# .. toggle_name: DISABLE_DEPRECATED_SIGNIN_URL
Expand Down
3 changes: 3 additions & 0 deletions cms/envs/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
CREDENTIALS_INTERNAL_SERVICE_URL = 'http://localhost:18150'
CREDENTIALS_PUBLIC_SERVICE_URL = 'http://localhost:18150'

############################ AI_TRANSLATIONS ##################################
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'

#################### Event bus backend ########################

EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer'
Expand Down
3 changes: 3 additions & 0 deletions cms/envs/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ def get_env_setting(setting):
################### Discussions micro frontend Feedback URL###################
DISCUSSIONS_MFE_FEEDBACK_URL = ENV_TOKENS.get('DISCUSSIONS_MFE_FEEDBACK_URL', DISCUSSIONS_MFE_FEEDBACK_URL)

############################ AI_TRANSLATIONS URL ##################################
AI_TRANSLATIONS_API_URL = ENV_TOKENS.get('AI_TRANSLATIONS_API_URL', AI_TRANSLATIONS_API_URL)

############## DRF overrides ##############
REST_FRAMEWORK.update(ENV_TOKENS.get('REST_FRAMEWORK', {}))

Expand Down
13 changes: 9 additions & 4 deletions lms/djangoapps/courseware/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


import ast
import re
import json
from collections import OrderedDict
from datetime import timedelta
Expand Down Expand Up @@ -450,11 +451,15 @@ def get_context_dict_from_string(data):
Retrieve dictionary from string.
"""
# Replace tuple and un-necessary info from inside string and get the dictionary.
cleaned_data = ast.literal_eval(data.split('((\'video.html\',')[1].replace("),\n {})", '').strip())
cleaned_data['metadata'] = OrderedDict(
sorted(json.loads(cleaned_data['metadata']).items(), key=lambda t: t[0])
cleaned_data = data.split('((\'video.html\',')[1].replace("),\n {})", '').strip()
# Omit user_id validation
cleaned_data_without_user = re.sub(".*user_id.*\n?", '', cleaned_data)

validated_data = ast.literal_eval(cleaned_data_without_user)
validated_data['metadata'] = OrderedDict(
sorted(json.loads(validated_data['metadata']).items(), key=lambda t: t[0])
)
return cleaned_data
return validated_data


def set_preview_mode(preview_mode: bool):
Expand Down
33 changes: 31 additions & 2 deletions lms/djangoapps/courseware/tests/test_video_mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def test_video_constructor(self):
'lmsRootURL': settings.LMS_ROOT_URL,
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'aiTranslationsUrl': settings.AI_TRANSLATIONS_API_URL,
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
'completionEnabled': False,
Expand All @@ -138,6 +139,8 @@ def test_video_constructor(self):
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': '',
}

mako_service = self.block.runtime.service(self.block, 'mako')
Expand Down Expand Up @@ -209,6 +212,7 @@ def test_video_constructor(self):
'lmsRootURL': settings.LMS_ROOT_URL,
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'aiTranslationsUrl': settings.AI_TRANSLATIONS_API_URL,
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
'completionEnabled': False,
Expand All @@ -223,6 +227,8 @@ def test_video_constructor(self):
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': '',
}

mako_service = self.block.runtime.service(self.block, 'mako')
Expand Down Expand Up @@ -365,6 +371,7 @@ def setUp(self):
'lmsRootURL': settings.LMS_ROOT_URL,
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'aiTranslationsUrl': settings.AI_TRANSLATIONS_API_URL,
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
'completionEnabled': False,
Expand Down Expand Up @@ -465,6 +472,8 @@ def test_get_html_track(self):
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': '',
}

for data in cases:
Expand Down Expand Up @@ -595,6 +604,8 @@ def test_get_html_source(self):
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': '',
}
initial_context['metadata']['duration'] = None

Expand Down Expand Up @@ -707,6 +718,7 @@ def test_get_html_with_mocked_edx_video_id(self):
metadata = self.default_metadata_dict
metadata['autoplay'] = False
metadata['sources'] = ""

initial_context = {
'autoadvance_enabled': False,
'branding_info': None,
Expand All @@ -730,6 +742,8 @@ def test_get_html_with_mocked_edx_video_id(self):
],
'poster': 'null',
'metadata': metadata,
'transcript_feedback_enabled': False,
'video_id': 'mock item',
}

DATA = SOURCE_XML.format( # lint-amnesty, pylint: disable=invalid-name
Expand Down Expand Up @@ -884,6 +898,7 @@ def helper_get_html_with_edx_video_id(self, data):
# Video found for edx_video_id
metadata = self.default_metadata_dict
metadata['sources'] = ""

initial_context = {
'autoadvance_enabled': False,
'branding_info': None,
Expand All @@ -907,6 +922,8 @@ def helper_get_html_with_edx_video_id(self, data):
],
'poster': 'null',
'metadata': metadata,
'transcript_feedback_enabled': False,
'video_id': data['edx_video_id'].replace('\t', ' '),
}

# pylint: disable=invalid-name
Expand Down Expand Up @@ -1024,6 +1041,8 @@ def side_effect(*args, **kwargs): # lint-amnesty, pylint: disable=unused-argume
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': 'vid-v1:12345',
}
initial_context['metadata']['duration'] = None

Expand Down Expand Up @@ -1122,6 +1141,8 @@ def test_get_html_cdn_source_external_video(self):
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': 'vid-v1:12345',
}
initial_context['metadata']['duration'] = None

Expand Down Expand Up @@ -2336,6 +2357,7 @@ def test_bumper_metadata(self, get_url_for_profiles, get_bumper_settings, is_bum

content = self.block.student_view(None).content
sources = ['example.mp4', 'example.webm']

expected_context = {
'autoadvance_enabled': False,
'branding_info': None,
Expand Down Expand Up @@ -2391,6 +2413,7 @@ def test_bumper_metadata(self, get_url_for_profiles, get_bumper_settings, is_bum
'lmsRootURL': settings.LMS_ROOT_URL,
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'aiTranslationsUrl': settings.AI_TRANSLATIONS_API_URL,
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
'completionEnabled': False,
Expand All @@ -2407,7 +2430,9 @@ def test_bumper_metadata(self, get_url_for_profiles, get_bumper_settings, is_bum
'poster': json.dumps(OrderedDict({
'url': 'http://img.youtube.com/vi/ZwkTiUPN0mg/0.jpg',
'type': 'youtube'
}))
})),
'transcript_feedback_enabled': False,
'video_id': '',
}

mako_service = self.block.runtime.service(self.block, 'mako')
Expand All @@ -2431,6 +2456,7 @@ def prepare_expected_context(self, autoadvanceenabled_flag, autoadvance_flag):
Build a dictionary with data expected by some operations in this test.
Only parameters related to auto-advance are variable, rest is fixed.
"""

context = {
'autoadvance_enabled': autoadvanceenabled_flag,
'branding_info': None,
Expand Down Expand Up @@ -2474,6 +2500,7 @@ def prepare_expected_context(self, autoadvanceenabled_flag, autoadvance_flag):
'transcriptAvailableTranslationsUrl': self.block.runtime.handler_url(
self.block, 'transcript', 'available_translations'
).rstrip('/?'),
'aiTranslationsUrl': settings.AI_TRANSLATIONS_API_URL,
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
'completionEnabled': False,
Expand All @@ -2487,7 +2514,9 @@ def prepare_expected_context(self, autoadvanceenabled_flag, autoadvance_flag):
{'display_name': 'SubRip (.srt) file', 'value': 'srt'},
{'display_name': 'Text (.txt) file', 'value': 'txt'}
],
'poster': 'null'
'poster': 'null',
'transcript_feedback_enabled': False,
'video_id': '',
}
return context

Expand Down
3 changes: 3 additions & 0 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5337,6 +5337,9 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring
EXPIRED_NOTIFICATIONS_DELETE_BATCH_SIZE = 10000
NOTIFICATION_CREATION_BATCH_SIZE = 99

############################ AI_TRANSLATIONS ##################################
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'

#### django-simple-history##
# disable indexing on date field its coming from django-simple-history.
SIMPLE_HISTORY_DATE_INDEX = False
Expand Down
3 changes: 3 additions & 0 deletions lms/envs/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,9 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
API_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/'
AUTH_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/authentication/index.html'

############################ AI_TRANSLATIONS ##################################
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'

################# New settings must go ABOVE this line #################
########################################################################
# See if the developer has any local overrides.
Expand Down
3 changes: 3 additions & 0 deletions lms/envs/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,9 @@ def get_env_setting(setting):
################### Discussions micro frontend Feedback URL###################
DISCUSSIONS_MFE_FEEDBACK_URL = ENV_TOKENS.get('DISCUSSIONS_MFE_FEEDBACK_URL', DISCUSSIONS_MFE_FEEDBACK_URL)

############################ AI_TRANSLATIONS URL ##################################
AI_TRANSLATIONS_API_URL = ENV_TOKENS.get('AI_TRANSLATIONS_API_URL', AI_TRANSLATIONS_API_URL)

############## DRF overrides ##############
REST_FRAMEWORK.update(ENV_TOKENS.get('REST_FRAMEWORK', {}))

Expand Down
Loading

0 comments on commit e51c01b

Please sign in to comment.