diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7601678597..969adcd7e4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,10 @@ Unreleased ---------- * nothing unreleased +[4.21.0] +--------- +* refactor: replace openai usage with xpert api + [4.20.14] --------- * chore: Update requirements diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 39d3c34b3a..77b47b0188 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,4 +2,4 @@ Your project description goes here. """ -__version__ = "4.20.14" +__version__ = "4.21.0" diff --git a/enterprise/api_client/open_ai.py b/enterprise/api_client/open_ai.py deleted file mode 100644 index c4c15af1e4..0000000000 --- a/enterprise/api_client/open_ai.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -OpenAI client -""" - -import openai - -from django.conf import settings - -openai.api_key = settings.OPENAI_API_KEY - - -def chat_completion(prompt, role, model='gpt-3.5-turbo'): - """ - Use chatGPT https://api.openai.com/v1/chat/completions endpoint to generate a response. - - Arguments: - prompt (str): ChatGPT prompt - role (str): ChatGPT role to assume for the prompt. - model (str): ChatGPT model to use for the prompt completion. - - Returns: - (str): Prompt response from OpenAI. - """ - response = openai.ChatCompletion.create( - model=model, - messages=[ - {'role': role, 'content': prompt}, - ] - ) - - return response['choices'][0]['message']['content'] diff --git a/enterprise/api_client/xpert_ai.py b/enterprise/api_client/xpert_ai.py new file mode 100644 index 0000000000..9686e004d1 --- /dev/null +++ b/enterprise/api_client/xpert_ai.py @@ -0,0 +1,40 @@ +""" +Xpert client +""" + +import json + +import requests + +from django.conf import settings + +CONNECT_TIMOUET_SECONDS = 5 +READ_TIMEOUT_SECONDS = 20 + + +def chat_completion(prompt, role): + """ + Generate response using xpert api. + + Arguments: + prompt (str): ChatGPT prompt + role (str): ChatGPT role to assume for the prompt. + + Returns: + (str): Prompt response from OpenAI. + """ + headers = { + 'Content-Type': 'application/json', + 'x-api-key': settings.CHAT_COMPLETION_API_KEY + } + + body = {'message_list': [{'role': role, 'content': prompt},]} + + response = requests.post( + settings.CHAT_COMPLETION_API, + headers=headers, + data=json.dumps(body), + timeout=(CONNECT_TIMOUET_SECONDS, READ_TIMEOUT_SECONDS) + ) + + return response.json().get('content') diff --git a/enterprise/models.py b/enterprise/models.py index ae05e2fc34..67566c8f1c 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -44,8 +44,8 @@ from enterprise.api_client.ecommerce import EcommerceApiClient from enterprise.api_client.enterprise_catalog import EnterpriseCatalogApiClient from enterprise.api_client.lms import EnrollmentApiClient, ThirdPartyAuthApiClient -from enterprise.api_client.open_ai import chat_completion from enterprise.api_client.sso_orchestrator import EnterpriseSSOOrchestratorApiClient +from enterprise.api_client.xpert_ai import chat_completion from enterprise.constants import ( ALL_ACCESS_CONTEXT, AVAILABLE_LANGUAGES, diff --git a/enterprise/settings/test.py b/enterprise/settings/test.py index c2c9032b14..b98da6eef5 100644 --- a/enterprise/settings/test.py +++ b/enterprise/settings/test.py @@ -353,7 +353,8 @@ def root(*args): # disable indexing on history_date. Otherwise it will add new alter migrations. SIMPLE_HISTORY_DATE_INDEX = False -OPENAI_API_KEY = '' +CHAT_COMPLETION_API = 'https://example.com/chat/completion' +CHAT_COMPLETION_API_KEY = 'i am a key' LEARNER_ENGAGEMENT_PROMPT_FOR_ACTIVE_CONTRACT = 'Create learner engagement report for active contracts.' LEARNER_ENGAGEMENT_PROMPT_FOR_NON_ACTIVE_CONTRACT = 'Create learner engagement report for non active contracts.' diff --git a/tests/test_enterprise/api/test_views.py b/tests/test_enterprise/api/test_views.py index 4435bf2e2f..e7ee9063db 100644 --- a/tests/test_enterprise/api/test_views.py +++ b/tests/test_enterprise/api/test_views.py @@ -7423,12 +7423,16 @@ def test_view_with_admin_user_tries(self): assert response.status_code == status.HTTP_403_FORBIDDEN assert response.json() == {'detail': 'Missing: enterprise.can_access_admin_dashboard'} - @mock.patch('enterprise.models.chat_completion') - def test_view_with_admin_user(self, mock_chat_completion): + @mock.patch('enterprise.api_client.xpert_ai.requests.post') + def test_view_with_admin_user(self, mock_post): """ Verify that an enterprise admin user having `enterprise.can_access_admin_dashboard` role can access the view. """ - mock_chat_completion.return_value = 'Test Response.' + xpert_response = 'Response from Xpert AI' + mock_response = mock.Mock() + mock_response.json.return_value = {'content': xpert_response} + mock_post.return_value = mock_response + self.set_jwt_cookie(ENTERPRISE_ADMIN_ROLE, self.enterprise_uuid) self.client.login(username=self.user.username, password=TEST_PASSWORD) @@ -7436,8 +7440,8 @@ def test_view_with_admin_user(self, mock_chat_completion): response = self.client.post(self.url, data=self.payload, format='json') assert response.status_code == status.HTTP_200_OK - assert 'learner_progress' in response.json() - assert 'learner_engagement' in response.json() + assert response.json()['learner_progress'] == xpert_response + assert response.json()['learner_engagement'] == xpert_response @mock.patch('enterprise.models.chat_completion') def test_404_if_enterprise_customer_does_not_exist(self, mock_chat_completion):