From bd1d098b19cbc262583bd153bef044c1f2d1eb3b Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 7 Dec 2024 15:54:26 +0530 Subject: [PATCH 1/4] feat: added test cases for feedback and threads --- pyproject.toml | 4 +- tests/configs/threads/sample.pdf | Bin 0 -> 54836 bytes tests/manual_test_async_feedback.py | 32 +++++++++++ tests/manual_test_async_thread_query.py | 67 ++++++++++++++++++++++++ tests/manual_test_feedback.py | 26 +++++++++ tests/manual_test_threads_query.py | 64 ++++++++++++++++++++++ 6 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 tests/configs/threads/sample.pdf create mode 100644 tests/manual_test_async_feedback.py create mode 100644 tests/manual_test_async_thread_query.py create mode 100644 tests/manual_test_feedback.py create mode 100644 tests/manual_test_threads_query.py diff --git a/pyproject.toml b/pyproject.toml index d1dc98c5..af3fd907 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.mypy] -exclude = 'portkey_ai/_vendor' +exclude = ['portkey_ai/_vendor', 'tests'] ignore_missing_imports = true follow_imports = "silent" disable_error_code = ['import-untyped', 'import-not-found'] @@ -16,4 +16,4 @@ ignore_errors = true force-exclude = '''(portkey_ai/_vendor)/''' [tool.ruff] -exclude = ["portkey_ai/_vendor"] \ No newline at end of file +exclude = ["portkey_ai/_vendor", "tests"] \ No newline at end of file diff --git a/tests/configs/threads/sample.pdf b/tests/configs/threads/sample.pdf new file mode 100644 index 0000000000000000000000000000000000000000..99d31cef1efdbb90fba2231a19974f4f74229be0 GIT binary patch literal 54836 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 None: + print("Step 1: Create Assistant") + assistant = Assistants(portkey).create( + model="gpt-4o-mini", + description="for testing purposes", + tools=[{"type": "file_search"}], + ) + print(assistant) + + print("Step 2: Create Upload") + upload = Uploads(portkey).create( + purpose="assistants", + bytes=os.stat(file_to_upload_path).st_size, # get total bytes + filename=file_to_upload_path.split("/")[-1], + mime_type="application/pdf", + ) + print(upload) + + print("Step 3: Create one or more parts for the upload_id received from step 1") + part = Uploads(portkey).parts.create( + data=open(file_to_upload_path, "rb").read(), upload_id=upload.id + ) + print(part) + + print("Step 4: Complete the upload") + complete_upload = Uploads(portkey).complete(upload_id=upload.id, part_ids=[part.id]) + print(complete_upload) + + print("Step 5: Create a run and poll") + run = portkey.beta.threads.create_and_run_poll( + thread={ + "messages": [ + { + "role": "user", + "content": "What is this document about?", + # Attach the new file to the message. + "attachments": [ + { + "file_id": complete_upload.file.id, + "tools": [{"type": "file_search"}], + } + ], + } + ] + }, + assistant_id=assistant.id, + ) + print(run) + + print("Step 6: Get the list of the messages") + messages = Messages(portkey).list(thread_id=run.thread_id) + print(messages) From a6bc5377e9797677268bc29f0ae75f677fde478e Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 7 Dec 2024 17:35:37 +0530 Subject: [PATCH 2/4] feat: added test cases for batches --- tests/manual_test_batches.py | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/manual_test_batches.py diff --git a/tests/manual_test_batches.py b/tests/manual_test_batches.py new file mode 100644 index 00000000..fc67aa7e --- /dev/null +++ b/tests/manual_test_batches.py @@ -0,0 +1,37 @@ +import os +from portkey_ai import Portkey + +portkey = Portkey( + api_key="Xgv7++HhSeF70UzdVSsmtJuGYe0=", + virtual_key="portkey-welcome-e248d3" +) + + +file_name = "/Users/chandeep/Downloads/seed_tasks.jsonl" + + +print("Step 1: Create a batch file") +batch_file = portkey.files.create( + file=open(file_name, "rb"), + purpose="batch" +) +print(batch_file) + + +print("Step 2: Create a batch job") +batch_job = portkey.batches.create( + input_file_id=batch_file.id, + endpoint="/v1/chat/completions", + completion_window="24h" +) +print(batch_job) + +print("Step 3: Retrieve the batch job") +batch_job = portkey.batches.retrieve(batch_job.id) +print(batch_job) + + +print("Step 4: Retrieve the result") +result_file_id = batch_job.output_file_id +result = portkey.files.content(result_file_id).content +print(result) \ No newline at end of file From ad1da4de66f5df4404525ead9d041c49edafaa89 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 7 Dec 2024 17:43:05 +0530 Subject: [PATCH 3/4] fix: file path --- tests/configs/batches/seed_tasks.jsonl | 21 +++++++++++++++++++++ tests/manual_test_batches.py | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/configs/batches/seed_tasks.jsonl diff --git a/tests/configs/batches/seed_tasks.jsonl b/tests/configs/batches/seed_tasks.jsonl new file mode 100644 index 00000000..35f42792 --- /dev/null +++ b/tests/configs/batches/seed_tasks.jsonl @@ -0,0 +1,21 @@ +{"id": "seed_task_1", "name": "complete_python_code", "instruction": "Suggest a completion for the following python code.", "instances": [{"input": "import json\n\ndef read_task_from_jsonl(data_file):\n '''This function will read a .jsonl file and return the ``task`` fields in all the lines.'''", "output": "import json\n\ndef read_task_from_jsonl(data_file):\n '''This function will read a .jsonl file and return the ``task`` fields in all the lines.'''\n with open(data_file) as fin:\n return [json.loads(line)['task'] for line in fin]"}], "is_classification": false} +{"id": "seed_task_2", "name": "code_todo", "instruction": "Using the comment as a guide, replace the \"TODO\" comment in the code with the proper code.", "instances": [{"input": "def greet_to(name):\n \"\"\"Print a greeting to the name provided.\"\"\"\n # TODO: assert name is a string\n print(\"Hello, \" + name + \"!\")", "output": "def greet_to(name):\n \"\"\"Print a greeting to the name provided.\"\"\"\n # assert name is a string\n assert isinstance(name, str), \"name must be a string\"\n print(\"Hello, \" + name + \"!\")"}], "is_classification": false} +{"id": "seed_task_3", "name": "python_code_generation", "instruction": "Generate a correct python program to fulfill the following purpose:", "instances": [{"input": "Count the occurrence of an element x in a list y.", "output": "def count_x(x, y):\n count = 0\n for i in range(y):\n if i == x:\n count += 1\n return count"}], "is_classification": false} +{"id": "seed_task_4", "name": "code_for_bitcoin_price", "instruction": "write a code to get the current value of a Bitcoin in US dollars using the bitcoincharts API.", "instances": [{"input": "", "output": "\"\"\"\nGet the current value of a Bitcoin in US dollars using the bitcoincharts api\n\"\"\"\n\nimport requests\nimport json\n\ndef get_bitcoin_price():\n url = 'http://api.bitcoincharts.com/v1/weighted_prices.json'\n response = requests.get(url)\n data = json.loads(response.text)\n return data['USD']['24h']\n \nif __name__ == '__main__':\n print(get_bitcoin_price())"}], "is_classification": false} +{"id": "seed_task_5", "name": "program_for_summation", "instruction": "Write a program to compute the sum of integers from k to n.", "instances": [{"input": "", "output": "def sum(k, n):\n sum = 0\n for i in range(k, n+1):\n sum += i\n return sum"}], "is_classification": false} +{"id": "seed_task_6", "name": "javascript_date_and_time", "instruction": "Write a script in JavaScript for printing the current date and time.", "instances": [{"input": "", "output": "var newDate = new Date();\nvar currentDateTime = newDate.toLocaleString();\nconsole.log(currentDateTime);"}], "is_classification": false} +{"id": "seed_task_7", "name": "python_leetcode", "instruction": "Write Python code to solve this leetcode problem.", "instances": [{"input": "Problem: You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.\n\nYou may assume the two numbers do not contain any leading zero, except the number 0 itself.", "output": "class Solution(object):\n def addTwoNumbers(self, l1, l2):\n \"\"\"\n :type l1: ListNode\n :type l2: ListNode\n :rtype: ListNode\n \"\"\"\n carry = 0\n root = n = ListNode(0)\n while l1 or l2 or carry:\n v1 = v2 = 0\n if l1:\n v1 = l1.val\n l1 = l1.next\n if l2:\n v2 = l2.val\n l2 = l2.next\n carry, val = divmod(v1+v2+carry, 10)\n n.next = ListNode(val)\n n = n.next\n return root.next"}], "is_classification": false} +{"id": "seed_task_8", "name": "pos_tag_for_word", "instruction": "Identify the pos tag of the word in the given sentence.", "instances": [{"input": "Word: excited\nSentence: She felt so excited that her application got approval.", "output": "Adjective, JJ."}], "is_classification": true} +{"id": "seed_task_9", "name": "code_syntax_error", "instruction": "You need to read a code and detect if there is a syntax error or not. Outpus true if there is error, output false if there is not.", "instances": [{"input": "def quick_sort(arr):\n if len(arr) < 2:\n return arr\n else:\n pivot = arr[0]\n less = [i for i in arr[1:] if i <= pivot]\n greater = [i for i in arr[1:] if i > pivot]\n return quick_sort(less) + [pivot] + quick_sort(greater)", "output": "false"}], "is_classification": true} +{"id": "seed_task_10", "name": "find_prime_numbers", "instruction": "Write a Python function to find all prime numbers up to the given number n.", "instances": [{"input": "", "output": "def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\ndef find_prime_numbers(n):\n primes = []\n for i in range(2, n + 1):\n if is_prime(i):\n primes.append(i)\n return primes"}], "is_classification": false} +{"id": "seed_task_11", "name": "csharp_hello_world", "instruction": "Write a simple C# program that prints \"Hello, World!\".", "instances": [{"input": "", "output": "using System;\n\nnamespace HelloWorld\n{\n class Program\n {\n static void Main(string[] args)\n {\n Console.WriteLine(\"Hello, World!\");\n }\n }\n}"}], "is_classification": false} +{"id": "seed_task_12", "name": "sql_query", "instruction": "Write an SQL query to select all columns from a table named 'employees' where the age is greater than 30.", "instances": [{"input": "", "output": "SELECT * FROM employees WHERE age > 30;"}], "is_classification": false} +{"id": "seed_task_13", "name": "palindrome_check", "instruction": "Write a Python function to check if a given word is a palindrome or not. A palindrome is a word that reads the same backwards as forwards.", "instances": [{"input": "", "output": "def is_palindrome(word):\n return word == word[::-1]"}], "is_classification": false} +{"id": "seed_task_14", "name": "javascript_alert", "instruction": "Write a JavaScript code snippet to show an alert message with the text \"Welcome to my website!\".", "instances": [{"input": "", "output": "alert('Welcome to my website!');"}], "is_classification": false} +{"id": "seed_task_15", "name": "python_reverse_list", "instruction": "Write a Python function to reverse a given list of integers.", "instances": [{"input": "", "output": "def reverse_list(numbers):\n return numbers[::-1]"}], "is_classification": false} +{"id": "seed_task_16", "name": "html_basic_structure", "instruction": "Write a basic HTML structure with a title \"My First Web Page\".", "instances": [{"input": "", "output": "\n\n\n \n \n My First Web Page\n\n\n\n\n"}], "is_classification": false} +{"id": "seed_task_17", "name": "c_plus_plus_hello_world", "instruction": "Write a simple C++ program that prints \"Hello, World!\".", "instances": [{"input": "", "output": "#include \n\nint main() {\n std::cout << \"Hello, World!\" << std::endl;\n return 0;\n}"}], "is_classification": false} +{"id": "seed_task_18", "name": "python_summation", "instruction": "Write a Python function that takes two numbers as input and returns their sum.", "instances": [{"input": "5, 7", "output": "def add_numbers(a, b):\n return a + b\n\nresult = add_numbers(5, 7)\nprint(result)"}], "is_classification": false} +{"id": "seed_task_19", "name": "java_loop_array", "instruction": "Create a JavaScript function that takes an array of numbers and returns the product of all elements.", "instances": [{"input": "[2, 3, 4]", "output": "function multiplyArrayElements(arr) {\n let product = 1;\n for (const num of arr) {\n product *= num;\n }\n return product;\n}\n\nconst result = multiplyArrayElements([2, 3, 4]);\nconsole.log(result);"}], "is_classification": false} +{"id": "seed_task_20", "name": "shell_total_lines_in_txt_file", "instruction": "Can you provide a shell script that displays the total number of lines in all '*.txt' files in the current directory?", "instances": [{"input": "\"file1.txt:\\nHello\\nWorld\\n\\nfile2.txt:\\nAnother\\nExample\"", "output": "#!/bin/sh\n\ntotal_lines=0\n\nfor file in *.txt; do\n lines=$(wc -l < \"$file\")\n total_lines=$((total_lines + lines))\ndone\n\necho \"Total lines: $total_lines\""}], "is_classification": false} +{"id": "seed_task_21", "name": "java_reverse_string_no_builtin", "instruction": "Implement a Java method to reverse a string without using any built-in functions.", "instances": [{"input": "\"Hello, World!\"", "output": "public class StringReversal {\n public static String reverseString(String input) {\n char[] charArray = input.toCharArray();\n int left = 0;\n int right = charArray.length - 1;\n\n while (left < right) {\n char temp = charArray[left];\n charArray[left] = charArray[right];\n charArray[right] = temp;\n\n left++;\n right--;\n }\n return new String(charArray);\n }\n\n public static void main(String[] args) {\n String str = \"Hello, World!\";\n System.out.println(\"Reversed string: \" + reverseString(str));\n }\n}"}], "is_classification": false} \ No newline at end of file diff --git a/tests/manual_test_batches.py b/tests/manual_test_batches.py index fc67aa7e..546f720e 100644 --- a/tests/manual_test_batches.py +++ b/tests/manual_test_batches.py @@ -7,7 +7,7 @@ ) -file_name = "/Users/chandeep/Downloads/seed_tasks.jsonl" +file_name = "./tests/configs/batches/seed_tasks.jsonl" print("Step 1: Create a batch file") From eaa65b6cf7bf4ff2dc7e24d1e79f3ce59039e91b Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 7 Dec 2024 17:44:02 +0530 Subject: [PATCH 4/4] fix: linting --- tests/manual_test_async_thread_query.py | 9 ++++++--- tests/manual_test_batches.py | 16 ++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/manual_test_async_thread_query.py b/tests/manual_test_async_thread_query.py index 910eaee2..ddc00b38 100644 --- a/tests/manual_test_async_thread_query.py +++ b/tests/manual_test_async_thread_query.py @@ -10,6 +10,7 @@ file_to_upload_path = "./tests/configs/threads/sample.pdf" + async def main(): print("Step 1: Create Assistant") assistant = await AsyncAssistants(portkey).create( @@ -35,7 +36,9 @@ async def main(): print(part) print("Step 4: Complete the upload") - complete_upload = await AsyncUploads(portkey).complete(upload_id=upload.id, part_ids=[part.id]) + complete_upload = await AsyncUploads(portkey).complete( + upload_id=upload.id, part_ids=[part.id] + ) print(complete_upload) print("Step 5: Create a run and poll") @@ -61,7 +64,7 @@ async def main(): print("Step 6: Get the list of the messages") messages = await AsyncMessages(portkey).list(thread_id=run.thread_id) - print(messages) + print(messages) -asyncio.run(main()) \ No newline at end of file +asyncio.run(main()) diff --git a/tests/manual_test_batches.py b/tests/manual_test_batches.py index 546f720e..633607a6 100644 --- a/tests/manual_test_batches.py +++ b/tests/manual_test_batches.py @@ -2,8 +2,7 @@ from portkey_ai import Portkey portkey = Portkey( - api_key="Xgv7++HhSeF70UzdVSsmtJuGYe0=", - virtual_key="portkey-welcome-e248d3" + api_key="Xgv7++HhSeF70UzdVSsmtJuGYe0=", virtual_key="portkey-welcome-e248d3" ) @@ -11,18 +10,15 @@ print("Step 1: Create a batch file") -batch_file = portkey.files.create( - file=open(file_name, "rb"), - purpose="batch" -) +batch_file = portkey.files.create(file=open(file_name, "rb"), purpose="batch") print(batch_file) print("Step 2: Create a batch job") batch_job = portkey.batches.create( - input_file_id=batch_file.id, - endpoint="/v1/chat/completions", - completion_window="24h" + input_file_id=batch_file.id, + endpoint="/v1/chat/completions", + completion_window="24h", ) print(batch_job) @@ -34,4 +30,4 @@ print("Step 4: Retrieve the result") result_file_id = batch_job.output_file_id result = portkey.files.content(result_file_id).content -print(result) \ No newline at end of file +print(result)