diff --git a/dev_gpt/options/generate/chains/auto_refine_description.py b/dev_gpt/options/generate/chains/auto_refine_description.py new file mode 100644 index 0000000..ea21c8f --- /dev/null +++ b/dev_gpt/options/generate/chains/auto_refine_description.py @@ -0,0 +1,57 @@ +import json + +from dev_gpt.apis.gpt import ask_gpt +from dev_gpt.options.generate.chains.extract_information import extract_information +from dev_gpt.options.generate.parser import identity_parser +from dev_gpt.options.generate.prompt_factory import context_to_string + + + +def auto_refine_description(context): + context['microservice_description'] = ask_gpt( + better_description_prompt, + identity_parser, + context_string=context_to_string(context) + ) + context['request_schema'] = ask_gpt( + generate_request_schema_prompt, + identity_parser, + context_string=context_to_string(context) + ) + context['response_schema'] = ask_gpt( + generate_output_schema_prompt, + identity_parser, + context_string=context_to_string(context) + ) + context['microservice_description'] = ask_gpt( + summarize_description_and_schemas_prompt, + identity_parser, + context_string=context_to_string(context) + ) + # details = extract_information(context['microservice_description'], ['database connection details', 'URL', 'secret']) + # if details: + # context['microservice_description'] += '\n\nAdditional information:' + json.dumps(details, indent=4) + # del context['details'] + + +better_description_prompt = f'''{{context_string}} +Update the description of the Microservice to make it more precise without adding or removing information. +Note: the output must be a list of tasks the Microservice has to perform. +Example for the description: "return the average temperature of the 5 days weather forecast for a given location." +1. get the 5 days weather forcast from the https://openweathermap.org/ API +2. extract the temperature from the response +3. calculate the average temperature''' + +generate_request_schema_prompt = '''{context_string} +Generate the lean request json schema of the Microservice. +Note: If you are not sure about the details, then come up with the minimal number of parameters possible.''' + +generate_output_schema_prompt = '''{context_string} +Generate the lean response json schema for the Microservice. +Note: If you are not sure about the details, then come up with the minimal number of parameters possible.''' + +summarize_description_and_schemas_prompt = '''{context_string} +Write an updated microservice description by incorporating information about the request and response parameters in a concise way without losing any information. +Note: You must not mention any details about algorithms or the technical implementation. +Note: You must not mention that there is a request and response JSON schema +Note: You must not use any formatting like triple backticks.''' diff --git a/dev_gpt/options/generate/chains/extract_information.py b/dev_gpt/options/generate/chains/extract_information.py new file mode 100644 index 0000000..5816a85 --- /dev/null +++ b/dev_gpt/options/generate/chains/extract_information.py @@ -0,0 +1,29 @@ +from typing import Dict + +from dev_gpt.apis.gpt import ask_gpt +from dev_gpt.options.generate.chains.question_answering import answer_yes_no_question +from dev_gpt.options.generate.parser import identity_parser, boolean_parser + + +def extract_information(text, info_keys) -> Dict[str, str]: + extracted_infos = {} + for info_key in info_keys: + is_information_in_text = answer_yes_no_question(text, f'Is a {info_key} mentioned above?') + if is_information_in_text: + extracted_info = ask_gpt( + extract_information_prompt, + identity_parser, + text=text, + info_key=info_key + ) + extracted_infos[info_key] = extracted_info + return extracted_infos + + +extract_information_prompt = '''\ +{text} + +Your task: +Return all {info_key}s from above.' +Note: you must only output your answer. +''' \ No newline at end of file diff --git a/dev_gpt/options/generate/chains/get_user_input_if_needed.py b/dev_gpt/options/generate/chains/get_user_input_if_needed.py index e99d227..522dbae 100644 --- a/dev_gpt/options/generate/chains/get_user_input_if_needed.py +++ b/dev_gpt/options/generate/chains/get_user_input_if_needed.py @@ -4,13 +4,14 @@ from dev_gpt.options.generate.parser import identity_parser def get_user_input_if_needed(context, conditions, question_gen_prompt_part): - if all([c(context) for c in conditions]): - return ask_gpt( + if all([c(context_to_string(context)) for c in conditions]): + question_to_user = ask_gpt( generate_question_for_file_input_prompt, identity_parser, context_string=context_to_string(context), question_gen_prompt_part=question_gen_prompt_part ) + return input(question_to_user) return None generate_question_for_file_input_prompt = '''\ diff --git a/dev_gpt/options/generate/chains/question_answering.py b/dev_gpt/options/generate/chains/question_answering.py new file mode 100644 index 0000000..6ff9f22 --- /dev/null +++ b/dev_gpt/options/generate/chains/question_answering.py @@ -0,0 +1,16 @@ +from dev_gpt.apis.gpt import ask_gpt +from dev_gpt.options.generate.parser import boolean_parser + + +def answer_yes_no_question(text, question): + prompt = question_prompt.format( + question=question, + text=text + ) + return ask_gpt(prompt, boolean_parser) + +question_prompt = '''\ +{text} +{question} +Note: You must answer "yes" or "no". +''' \ No newline at end of file diff --git a/dev_gpt/options/generate/condition.py b/dev_gpt/options/generate/condition.py index fdcd46b..3049008 100644 --- a/dev_gpt/options/generate/condition.py +++ b/dev_gpt/options/generate/condition.py @@ -1,22 +1,10 @@ -from dev_gpt.apis.gpt import ask_gpt -from dev_gpt.options.generate.prompt_factory import context_to_string -from dev_gpt.options.generate.parser import boolean_parser +from dev_gpt.options.generate.chains.question_answering import answer_yes_no_question -def is_true(question): - def fn(context): - prompt = question_prompt.format( - question=question, - context_string=context_to_string(context) - ) - return ask_gpt(prompt, boolean_parser) +def is_question_true(question): + def fn(text): + return answer_yes_no_question(text, question) return fn -def is_false(question): - return lambda context: not is_true(question)(context) - -question_prompt = '''\ -{context_string} -{question} -Note: You must answer "yes" or "no". -''' \ No newline at end of file +def is_question_false(question): + return lambda context: not is_question_true(question)(context) diff --git a/dev_gpt/options/generate/pm/pm.py b/dev_gpt/options/generate/pm/pm.py index 978dcca..34382c1 100644 --- a/dev_gpt/options/generate/pm/pm.py +++ b/dev_gpt/options/generate/pm/pm.py @@ -1,7 +1,8 @@ from dev_gpt.apis import gpt from dev_gpt.apis.gpt import ask_gpt +from dev_gpt.options.generate.chains.auto_refine_description import auto_refine_description from dev_gpt.options.generate.chains.user_confirmation_feedback_loop import user_feedback_loop -from dev_gpt.options.generate.condition import is_false, is_true +from dev_gpt.options.generate.condition import is_question_false, is_question_true from dev_gpt.options.generate.chains.get_user_input_if_needed import get_user_input_if_needed from dev_gpt.options.generate.parser import identity_parser # from dev_gpt.options.generate.pm.task_tree_schema import TaskTree @@ -38,11 +39,9 @@ Description of the microservice: # return sub_task_tree def refine_description(self, microservice_description): - context = { - 'microservice_description': microservice_description - } - self.auto_refine_description(context) - user_feedback_loop(context, microservice_description) + context = {'microservice_description': microservice_description} + auto_refine_description(context) + microservice_description = user_feedback_loop(context, context['microservice_description']) test_description = ask_gpt( generate_test_description_prompt, @@ -56,8 +55,8 @@ Description of the microservice: 'Response schema': context['response_schema'], }, conditions=[ - is_true('Does request schema contain an example file url?'), - is_false('Is input url specified in the description?'), + is_question_true('Does request schema require a file?'), + # is_question_false('Is input url specified in the description?'), ], question_gen_prompt_part="Generate a question that asks for an example file url.", ) @@ -66,26 +65,7 @@ Description of the microservice: return microservice_description, test_description - def auto_refine_description(self, context): - context['microservice_description'] = ask_gpt( - better_description_prompt, - identity_parser, - **context - ) - context['request_schema'] = ask_gpt( - generate_request_schema_prompt, - identity_parser, - **context - ) - context['response_schema'] = ask_gpt( - generate_output_schema_prompt, - identity_parser, - **context - ) - context['microservice_description'] = ask_gpt( - summarize_description_and_schemas_prompt, identity_parser, - **context - ) + # def get_nlp_fns(self, microservice_description): # return ask_gpt( @@ -229,28 +209,10 @@ Microservice description: {microservice_description} ```''' -better_description_prompt = client_description + ''' -Update the description of the Microservice to make it more precise without adding or removing information. -Note: the output must be a list of tasks the Microservice has to perform. -Example for the description: "return the average temperature of the 5 days weather forecast for a given location." -1. get the 5 days weather forcast from the https://openweathermap.org/ API -2. extract the temperature from the response -3. calculate the average temperature''' # better_description_prompt = client_description + ''' # Update the description of the Microservice to make it more precise without adding or removing information.''' -generate_request_schema_prompt = client_description + ''' -Generate the lean request json schema of the Microservice. -Note: If you are not sure about the details, then come up with the minimal number of parameters possible.''' - -generate_output_schema_prompt = client_description + ''' -request json schema: -``` -{request_schema} -``` -Generate the lean response json schema for the Microservice. -Note: If you are not sure about the details, then come up with the minimal number of parameters possible.''' # If we want to activate this back, then it first needs to work. Currently, it outputs "no" for too many cases. # is_feedback_valuable_prompt = client_description + ''' @@ -263,20 +225,6 @@ Note: If you are not sure about the details, then come up with the minimal numbe # Note: If the user does not want to provide feedback, then you must answer "no".''' -summarize_description_and_schemas_prompt = client_description + ''' -Request json schema: -``` -{request_schema} -``` -Response json schema: -``` -{response_schema} -``` -Write an updated microservice description by incorporating information about the request and response parameters in a concise way without losing any information. -Note: You must not mention any details about algorithms or the technical implementation. -Note: You must not mention that there is a request and response JSON schema -Note: You must not use any formatting like triple backticks.''' - # summarize_description_prompt = client_description + ''' diff --git a/test/integration/test_generator.py b/test/integration/test_generator.py index 23d7845..dceb5e1 100644 --- a/test/integration/test_generator.py +++ b/test/integration/test_generator.py @@ -51,7 +51,7 @@ But hey, at least SOMEONE's enjoying their lunch. #officelife\'''', assert generator.generate() == 0 -@pytest.mark.parametrize('mock_input_sequence', [['y']], indirect=True) +@pytest.mark.parametrize('mock_input_sequence', [['y', 'https://www.africau.edu/images/default/sample.pdf']], indirect=True) def test_generation_level_2(microservice_dir, mock_input_sequence): """ Requirements: @@ -64,7 +64,7 @@ def test_generation_level_2(microservice_dir, mock_input_sequence): """ os.environ['VERBOSE'] = 'true' generator = Generator( - "The input is a PDF like https://www.africau.edu/images/default/sample.pdf and the output the summarized text (50 words).", + "The input is a PDF and the output the summarized text (50 words).", str(microservice_dir), 'gpt-3.5-turbo' ) @@ -95,7 +95,7 @@ Example input: 'AAPL' ) assert generator.generate() == 0 -@pytest.mark.parametrize('mock_input_sequence', [['y']], indirect=True) +@pytest.mark.parametrize('mock_input_sequence', [['y', 'https://www.signalogic.com/melp/EngSamples/Orig/ENG_M.wav']], indirect=True) def test_generation_level_4(microservice_dir, mock_input_sequence): """ Requirements: @@ -125,14 +125,13 @@ print('This is the text from the audio file:', response.json()['text']) 2. Summarize the text (~50 words) while still maintaining the key facts. 3. Create an audio file of the summarized text using a tts library. 4. Return the the audio file as base64 encoded binary. -Example input file: https://www.signalogic.com/melp/EngSamples/Orig/ENG_M.wav ''', str(microservice_dir), 'gpt-4' ) assert generator.generate() == 0 -@pytest.mark.parametrize('mock_input_sequence', [['y']], indirect=True) +@pytest.mark.parametrize('mock_input_sequence', [['y', 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/560px-PNG_transparency_demonstration_1.png']], indirect=True) def test_generation_level_5(microservice_dir, mock_input_sequence): """ Requirements: @@ -165,7 +164,6 @@ Result format: The description is then used to generate a joke. The joke is the put on the image. The output is the image with the joke on it. -Example input image: https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/560px-PNG_transparency_demonstration_1.png ''', str(microservice_dir), 'gpt-3.5-turbo'