From 112b07b707213595aafbdbff9215bb4333713626 Mon Sep 17 00:00:00 2001 From: Evgenii Abdrazakov Date: Fri, 14 Apr 2023 13:46:56 +0200 Subject: [PATCH 1/3] Prepared initial tests --- helpers/openAIHelper.py | 15 ++++++++------- service_routine/tests.py | 3 --- tests/test_helpers.py | 15 +++++++++++++++ tg_bot/models.py | 2 +- tg_bot/tests.py | 16 +++++++++++++++- 5 files changed, 39 insertions(+), 12 deletions(-) delete mode 100644 service_routine/tests.py create mode 100644 tests/test_helpers.py diff --git a/helpers/openAIHelper.py b/helpers/openAIHelper.py index c68db12..29a81e0 100644 --- a/helpers/openAIHelper.py +++ b/helpers/openAIHelper.py @@ -65,9 +65,9 @@ async def chatGPT_req(message, tg_chat, type: _TYPES, model='gpt-3.5-turbo', ini system_content = f"""Important: Provide ONLY the requested form in the output and no other text!!!""" messages = [ - {"role": "system", "content": system_content}, - {"role": "user", "content": message} - ] + {"role": "system", "content": system_content}, + {"role": "user", "content": message} + ] if examples and len(examples) > 0: messages.append(examples) chatgpt_response = openai.ChatCompletion.create( @@ -99,6 +99,7 @@ def parse_response(response, tg_chat, words_limit, type, initial_text): else: return message + def parse_reminder_probability(text): return_val = parse_json(text) if 'reminder_probability' in return_val: @@ -110,15 +111,14 @@ def parse_reminder_probability(text): else: return 5 + def parse_json(text): pattern = r"{.*}" json_dict = {} text = "{" + text.split("{", 1)[1] # remove the text before the JSON - text = text.split("}", 1)[0] + "}" # remove the text after the JSON + text = text.split("}", 1)[0] + "}" # remove the text after the JSON text = text.replace("\'", "\"") text = replace_bools(text) - print(text) - print(type(text)) try: return json.loads(text) except Exception as e: @@ -131,5 +131,6 @@ def parse_json(text): print(json_dict) return json_dict + def replace_bools(text): - return text.replace('True', 'true').replace('False', 'false') \ No newline at end of file + return text.replace('True', 'true').replace('False', 'false') diff --git a/service_routine/tests.py b/service_routine/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/service_routine/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..026e74e --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,15 @@ +from helpers.openAIHelper import * + +from django.test import TestCase + + +class ParseResponseCase(TestCase): + input_text = "Here is your output: {'is_reminder': True, 'is_event': False}" + output_parsable_expected = "Here is your output: {'is_reminder': true, 'is_event': false}" + output_parsed_json = {"is_reminder": True, "is_event": False} + + def test_bool_replaced(self): + self.assertEqual(replace_bools(self.input_text), self.output_parsable_expected) + + def test_parse_json(self): + self.assertEqual(parse_json(self.input_text), self.output_parsed_json) diff --git a/tg_bot/models.py b/tg_bot/models.py index 777ab73..1b58057 100644 --- a/tg_bot/models.py +++ b/tg_bot/models.py @@ -28,4 +28,4 @@ def money_used(self): class ChatAdmin(admin.ModelAdmin): - list_display = ['id', 'username', 'chat_id', 'is_approved', 'role', 'language', 'money_used', 'last_conversation'] + list_display = ['id', 'username', 'chat_id', 'counter', 'is_approved', 'expenses', 'money_used'] diff --git a/tg_bot/tests.py b/tg_bot/tests.py index 7ce503c..5b8f2d5 100644 --- a/tg_bot/tests.py +++ b/tg_bot/tests.py @@ -1,3 +1,17 @@ from django.test import TestCase +from tg_bot.models import Chat -# Create your tests here. + +# ToDo: Modify the test to execute correctly with the tg_bot.models - class Chat, instead of sample 'Animal' +# run with python manage.py test +class AnimalTestCase(TestCase): + def setUp(self): + Animal.objects.create(name="lion", sound="roar") + Animal.objects.create(name="cat", sound="meow") + + def test_animals_can_speak(self): + """Animals that can speak are correctly identified""" + lion = Animal.objects.get(name="lion") + cat = Animal.objects.get(name="cat") + self.assertEqual(lion.speak(), 'The lion says "roar"') + self.assertEqual(cat.speak(), 'The cat says "meow"') From 7ce8392fcdf3d617f2aac01d2da13642169f20f3 Mon Sep 17 00:00:00 2001 From: Kikrotobi Date: Thu, 20 Apr 2023 00:54:40 +0200 Subject: [PATCH 2/3] Add tests --- helpers/localClassifiers.py | 24 +++++ tests/test_helpers.py | 208 +++++++++++++++++++++++++++++++++++- tg_bot/tests.py | 36 +++++-- 3 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 helpers/localClassifiers.py diff --git a/helpers/localClassifiers.py b/helpers/localClassifiers.py new file mode 100644 index 0000000..5c4bfc6 --- /dev/null +++ b/helpers/localClassifiers.py @@ -0,0 +1,24 @@ +import pickle +from io import BytesIO + +import numpy as np +import pandas as pd +from helpers.resourcesPacker import read_encrypted + + +def load_classifier(): + loaded_model_raw, f = read_encrypted('finalized_model.sav', is_normal_read=False) + loaded_vectorizer_raw, f = read_encrypted('vectorizer.sav', is_normal_read=False) + + loaded_model = pickle.load(BytesIO(loaded_model_raw)) + loaded_vectorizer = pickle.load(BytesIO(loaded_vectorizer_raw)) + + return loaded_model, loaded_vectorizer + + +async def predict_class(message): + model, vectorizer = load_classifier() + mine_df = pd.DataFrame({'message': [str(message)]}) + mine_test = vectorizer.transform(mine_df['message']) + probabilities = np.array(model.predict(mine_test)) + return probabilities[0] diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 026e74e..d9c117a 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,7 +1,10 @@ -from helpers.openAIHelper import * +import unittest +from helpers import MessageHistoryHelpers +from helpers.openAIHelper import * +from helpers.DatabaseHelpers import * from django.test import TestCase - +from telegram import Message class ParseResponseCase(TestCase): input_text = "Here is your output: {'is_reminder': True, 'is_event': False}" @@ -13,3 +16,204 @@ def test_bool_replaced(self): def test_parse_json(self): self.assertEqual(parse_json(self.input_text), self.output_parsed_json) + +class DatabaseHelpersTest(TestCase): + + @classmethod + def setUpClass(cls): + cls.DB_NAME = 'test_db' + cls.db_handle, cls.client = get_db_handle(db_name=cls.DB_NAME) + cls.collection_name = 'test_collection' + cls.collection_handle = get_collection_handle(cls.db_handle, cls.collection_name) + cls.chat_id = '12345' + cls.language = 'en' + cls.chat_data = { + "chat_id": cls.chat_id, + "counter": 0, + "language": cls.language, + "is_approved": False + } + cls.chat = Chat.objects.create( + chat_id=cls.chat_data['chat_id'], + counter=cls.chat_data['counter'], + language=cls.chat_data['language'], + is_approved=cls.chat_data['is_approved'] + ) + + @classmethod + def tearDownClass(cls): + cls.client.drop_database(cls.DB_NAME) + cls.client.close() + + def test_get_db_handle(self): + db_handle, client = get_db_handle(db_name=self.DB_NAME) + self.assertIsNotNone(db_handle) + self.assertIsNotNone(client) + self.assertIsInstance(db_handle, MongoClient) + self.assertIsInstance(client, MongoClient) + self.assertEqual(db_handle.name, self.DB_NAME) + + def test_get_collection_handle(self): + collection_handle = get_collection_handle(self.db_handle, self.collection_name) + self.assertIsNotNone(collection_handle) + self.assertIsInstance(collection_handle, MongoClient) + + def test_get_chat(self): + chat = get_chat(self.chat_id) + self.assertIsNotNone(chat) + self.assertIsInstance(chat, Chat) + self.assertEqual(chat.chat_id, self.chat_id) + + def test_get_creator(self): + creator = get_creator() + self.assertIsNotNone(creator) + self.assertIsInstance(creator, Chat) + self.assertEqual(creator.pk, 1) + + def test_set_language(self): + language = 'fr' + set_language(self.chat_id, language) + chat = get_chat(self.chat_id) + self.assertEqual(chat.language, language) + + def test_set_approved(self): + set_approved(self.chat_id, True) + chat = get_chat(self.chat_id) + self.assertTrue(chat.is_approved) + + def test_tick_counter(self): + chat = get_chat(self.chat_id) + prev_counter = chat.counter + tick_counter(self.chat_id) + chat = get_chat(self.chat_id) + self.assertEqual(chat.counter, prev_counter + 1) + + def test_tick_tokens(self): + chat = get_chat(self.chat_id) + prev_tokens = chat.tokens_used + tokens = 5 + tick_tokens(self.chat_id, tokens) + chat = get_chat(self.chat_id) + self.assertEqual(chat.tokens_used, prev_tokens + tokens) + + def test_assign_last_conversation(self): + conversation = 'test_conversation' + assign_last_conversation(self.chat_id, conversation) + chat = get_chat(self.chat_id) + self.assertEqual(chat.last_conversation, conversation) + + def test_assign_last_conversation(self): + conversation = 'test_conversation' + assign_last_conversation(self.chat_id, conversation) + chat = get_chat(self.chat_id) + self.assertEqual(chat.last_conversation, conversation) + + def test_return_records_list(self): + records_list = return_records_list([1, 2, 3, 4, 5]) + self.assertIsNotNone(records_list) + self.assertIsInstance(records_list, list) + self.assertEqual(records_list, [1, 2, 3, 4, 5]) + + def test_return_single_record(self): + record = return_single_record(123) + self.assertIsNotNone(record) + self.assertIsInstance(record, int) + self.assertEqual(record, 123) + + @sync_to_async + async def test_async_get_chat(self): + chat = await async_get_chat(self.chat_id) + self.assertIsNotNone(chat) + self.assertIsInstance(chat, Chat) + self.assertEqual(chat.chat_id, self.chat_id) + + @sync_to_async + async def test_async_get_creator(self): + creator = await async_get_creator() + self.assertIsNotNone(creator) + self.assertIsInstance(creator, Chat) + self.assertEqual(creator.pk, 1) + + @sync_to_async + async def test_async_set_language(self): + language = 'fr' + await async_set_language(self.chat_id, language) + chat = await async_get_chat(self.chat_id) + self.assertEqual(chat.language, language) + + @sync_to_async + async def test_async_set_approved(self): + await async_set_approved(self.chat_id, True) + chat = await async_get_chat(self.chat_id) + self.assertTrue(chat.is_approved) + + @sync_to_async + async def test_async_tick_counter(self): + chat = await async_get_chat(self.chat_id) + prev_counter = chat.counter + await async_tick_counter(self.chat_id) + chat = await async_get_chat(self.chat_id) + self.assertEqual(chat.counter, prev_counter + 1) + + @sync_to_async + async def test_async_tick_tokens(self): + chat = await async_get_chat(self.chat_id) + prev_tokens = chat.tokens_used + tokens = 5 + await async_tick_tokens(self.chat_id, tokens) + chat = await async_get_chat(self.chat_id) + self.assertEqual(chat.tokens_used, prev_tokens + tokens) + + @sync_to_async + async def test_async_assign_last_conversation(self): + conversation = 'test_conversation' + await async_assign_last_conversation(self.chat_id, conversation) + chat = await async_get_chat(self.chat_id) + self.assertEqual(chat.last_conversation, conversation) + + +class TestMessageHistoryHelpers(unittest.TestCase): + def setUp(self): + # Инициализация объекта MessageHistoryHelpers + self.message_history_helpers = MessageHistoryHelpers() + + def tearDown(self): + # Удаление временных данных после тестирования + # (например, удаление записей из базы данных) + pass + + def test_insert_input_message(self): + # Тест метода insert_input_message + # Создание тестового сообщения + in_msg = Message(chat_id=1, date=1234567890, message_id=1, chat=None, text='Test message') + # Вызов метода insert_input_message + result = self.message_history_helpers.insert_input_message(in_msg) + # Проверка наличия результата + self.assertIsNotNone(result) + + def test_insert_response(self): + # Тест метода insert_response + # Создание тестового сообщения + in_msg = Message(chat_id=1, date=1234567890, message_id=1, chat=None, text='Test message') + response_text = 'Test response' + tokens_used = 5 + # Вызов метода insert_response + result = self.message_history_helpers.insert_response(in_msg, response_text, tokens_used) + # Проверка наличия результата + self.assertIsNotNone(result) + + def test_get_messages_for_user(self): + # Тест метода get_messages_for_user + user_id = 1 + # Вызов метода get_messages_for_user + result = self.message_history_helpers.get_messages_for_user(user_id) + # Проверка типа результата + self.assertIsInstance(result, list) + + def test_get_last_user_messages(self): + # Тест метода get_last_user_messages + user_id = 1 + # Вызов метода get_last_user_messages + result = self.message_history_helpers.get_last_user_messages(user_id) + # Проверка типа результата + self.assertIsInstance(result, list) diff --git a/tg_bot/tests.py b/tg_bot/tests.py index 5b8f2d5..edb5ec4 100644 --- a/tg_bot/tests.py +++ b/tg_bot/tests.py @@ -2,16 +2,30 @@ from tg_bot.models import Chat -# ToDo: Modify the test to execute correctly with the tg_bot.models - class Chat, instead of sample 'Animal' -# run with python manage.py test -class AnimalTestCase(TestCase): +class ChatTestCase(TestCase): def setUp(self): - Animal.objects.create(name="lion", sound="roar") - Animal.objects.create(name="cat", sound="meow") + Chat.objects.create(chat_id="chat1", counter=0, tokens_used=0, is_approved=False, + role='none', language='english', last_conversation='', username='', + current_mode='chatGPT') - def test_animals_can_speak(self): - """Animals that can speak are correctly identified""" - lion = Animal.objects.get(name="lion") - cat = Animal.objects.get(name="cat") - self.assertEqual(lion.speak(), 'The lion says "roar"') - self.assertEqual(cat.speak(), 'The cat says "meow"') + Chat.objects.create(chat_id="chat2", counter=0, tokens_used=0, is_approved=False, + role='none', language='english', last_conversation='', username='', + current_mode='chatGPT') + + def test_money_used(self): + """Test money_used() method of Chat model""" + chat1 = Chat.objects.get(chat_id="chat1") + chat2 = Chat.objects.get(chat_id="chat2") + self.assertEqual(chat1.money_used(), '$ 0.0') # Ожидаемое значение при counter=0, tokens_used=0 + self.assertEqual(chat2.money_used(), '$ 0.0') # Ожидаемое значение при counter=0, tokens_used=0 + + # Изменяем значения полей и проверяем результат + chat1.counter = 10 + chat1.tokens_used = 100 + chat1.save() + chat2.counter = 20 + chat2.tokens_used = 200 + chat2.save() + + self.assertEqual(chat1.money_used(), '$ 0.002') # Ожидаемое значение при counter=10, tokens_used=100 + self.assertEqual(chat2.money_used(), '$ 0.004') From 6f5d0af89be87463c6900b9756f5dcb941328071 Mon Sep 17 00:00:00 2001 From: Ovaday Date: Thu, 20 Apr 2023 21:53:22 +0200 Subject: [PATCH 3/3] Resolved merge & new version changes --- helpers/localClassifiers.py | 24 ------------------------ tests/test_helpers.py | 16 +++++++++------- tg_bot/models.py | 2 +- tg_bot/tests.py | 10 ++++------ 4 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 helpers/localClassifiers.py diff --git a/helpers/localClassifiers.py b/helpers/localClassifiers.py deleted file mode 100644 index 5c4bfc6..0000000 --- a/helpers/localClassifiers.py +++ /dev/null @@ -1,24 +0,0 @@ -import pickle -from io import BytesIO - -import numpy as np -import pandas as pd -from helpers.resourcesPacker import read_encrypted - - -def load_classifier(): - loaded_model_raw, f = read_encrypted('finalized_model.sav', is_normal_read=False) - loaded_vectorizer_raw, f = read_encrypted('vectorizer.sav', is_normal_read=False) - - loaded_model = pickle.load(BytesIO(loaded_model_raw)) - loaded_vectorizer = pickle.load(BytesIO(loaded_vectorizer_raw)) - - return loaded_model, loaded_vectorizer - - -async def predict_class(message): - model, vectorizer = load_classifier() - mine_df = pd.DataFrame({'message': [str(message)]}) - mine_test = vectorizer.transform(mine_df['message']) - probabilities = np.array(model.predict(mine_test)) - return probabilities[0] diff --git a/tests/test_helpers.py b/tests/test_helpers.py index d9c117a..73c4ba3 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,5 +1,7 @@ import unittest +from asgiref.sync import async_to_sync + from helpers import MessageHistoryHelpers from helpers.openAIHelper import * from helpers.DatabaseHelpers import * @@ -120,34 +122,34 @@ def test_return_single_record(self): self.assertIsInstance(record, int) self.assertEqual(record, 123) - @sync_to_async + @async_to_sync async def test_async_get_chat(self): chat = await async_get_chat(self.chat_id) self.assertIsNotNone(chat) self.assertIsInstance(chat, Chat) self.assertEqual(chat.chat_id, self.chat_id) - @sync_to_async + @async_to_sync async def test_async_get_creator(self): creator = await async_get_creator() self.assertIsNotNone(creator) self.assertIsInstance(creator, Chat) self.assertEqual(creator.pk, 1) - @sync_to_async + @async_to_sync async def test_async_set_language(self): language = 'fr' await async_set_language(self.chat_id, language) chat = await async_get_chat(self.chat_id) self.assertEqual(chat.language, language) - @sync_to_async + @async_to_sync async def test_async_set_approved(self): await async_set_approved(self.chat_id, True) chat = await async_get_chat(self.chat_id) self.assertTrue(chat.is_approved) - @sync_to_async + @async_to_sync async def test_async_tick_counter(self): chat = await async_get_chat(self.chat_id) prev_counter = chat.counter @@ -155,7 +157,7 @@ async def test_async_tick_counter(self): chat = await async_get_chat(self.chat_id) self.assertEqual(chat.counter, prev_counter + 1) - @sync_to_async + @async_to_sync async def test_async_tick_tokens(self): chat = await async_get_chat(self.chat_id) prev_tokens = chat.tokens_used @@ -164,7 +166,7 @@ async def test_async_tick_tokens(self): chat = await async_get_chat(self.chat_id) self.assertEqual(chat.tokens_used, prev_tokens + tokens) - @sync_to_async + @async_to_sync async def test_async_assign_last_conversation(self): conversation = 'test_conversation' await async_assign_last_conversation(self.chat_id, conversation) diff --git a/tg_bot/models.py b/tg_bot/models.py index 1b58057..777ab73 100644 --- a/tg_bot/models.py +++ b/tg_bot/models.py @@ -28,4 +28,4 @@ def money_used(self): class ChatAdmin(admin.ModelAdmin): - list_display = ['id', 'username', 'chat_id', 'counter', 'is_approved', 'expenses', 'money_used'] + list_display = ['id', 'username', 'chat_id', 'is_approved', 'role', 'language', 'money_used', 'last_conversation'] diff --git a/tg_bot/tests.py b/tg_bot/tests.py index edb5ec4..6f79d4c 100644 --- a/tg_bot/tests.py +++ b/tg_bot/tests.py @@ -20,12 +20,10 @@ def test_money_used(self): self.assertEqual(chat2.money_used(), '$ 0.0') # Ожидаемое значение при counter=0, tokens_used=0 # Изменяем значения полей и проверяем результат - chat1.counter = 10 - chat1.tokens_used = 100 + chat1.expenses = 10 chat1.save() - chat2.counter = 20 - chat2.tokens_used = 200 + chat2.expenses = 0.2 chat2.save() - self.assertEqual(chat1.money_used(), '$ 0.002') # Ожидаемое значение при counter=10, tokens_used=100 - self.assertEqual(chat2.money_used(), '$ 0.004') + self.assertEqual(chat1.money_used(), f'$ {chat1.expenses}') # Ожидаемое значение при counter=10, tokens_used=100 + self.assertEqual(chat2.money_used(), f'$ {chat2.expenses}')