refactor: merge main

This commit is contained in:
Joschka Braun
2023-04-18 14:05:36 +02:00
parent eaac7e49b3
commit 0692976088
4 changed files with 80 additions and 53 deletions

View File

@@ -4,6 +4,7 @@ from time import sleep
from typing import List, Any from typing import List, Any
import openai import openai
from langchain import PromptTemplate
from langchain.callbacks import CallbackManager from langchain.callbacks import CallbackManager
from langchain.chat_models import ChatOpenAI from langchain.chat_models import ChatOpenAI
from openai.error import RateLimitError from openai.error import RateLimitError
@@ -88,12 +89,14 @@ class _GPTConversation:
@staticmethod @staticmethod
def _create_system_message(task_description, test_description, system_definition_examples: List[str] = []) -> SystemMessage: def _create_system_message(task_description, test_description, system_definition_examples: List[str] = []) -> SystemMessage:
system_message = system_message_base system_message = PromptTemplate.from_template(system_message_base).format(
task_description=task_description,
test_description=test_description,
)
if 'executor' in system_definition_examples: if 'executor' in system_definition_examples:
system_message += f'\n{executor_example}' system_message += f'\n{executor_example}'
if 'docarray' in system_definition_examples: if 'docarray' in system_definition_examples:
system_message += f'\n{docarray_example}' system_message += f'\n{docarray_example}'
if 'client' in system_definition_examples: if 'client' in system_definition_examples:
system_message += f'\n{client_example}' system_message += f'\n{client_example}'
# create from template
return SystemMessage(content=system_message) return SystemMessage(content=system_message)

View File

@@ -11,7 +11,7 @@ from src.options.generate.templates import template_generate_microservice_name,
template_solve_code_issue, \ template_solve_code_issue, \
template_solve_dependency_issue, template_is_dependency_issue, template_generate_playground, \ template_solve_dependency_issue, template_is_dependency_issue, template_generate_playground, \
template_generate_executor, template_generate_test, template_generate_requirements, template_generate_dockerfile, \ template_generate_executor, template_generate_test, template_generate_requirements, template_generate_dockerfile, \
template_chain_of_thought template_chain_of_thought, template_summarize_error
from src.utils.io import persist_file, get_all_microservice_files_with_content, get_microservice_path from src.utils.io import persist_file, get_all_microservice_files_with_content, get_microservice_path
from src.utils.string_tools import print_colored from src.utils.string_tools import print_colored
@@ -55,8 +55,6 @@ metas:
def generate_microservice( def generate_microservice(
self, self,
description,
test,
path, path,
microservice_name, microservice_name,
packages, packages,
@@ -70,9 +68,9 @@ metas:
microservice_content_raw = conversation.chat( microservice_content_raw = conversation.chat(
template_generate_executor.format( template_generate_executor.format(
microservice_name=microservice_name, microservice_name=microservice_name,
microservice_description=description, microservice_description=self.task_description,
test=test, test=self.test_description,
package=package, packages=packages,
file_name_purpose=EXECUTOR_FILE_NAME, file_name_purpose=EXECUTOR_FILE_NAME,
tag_name=EXECUTOR_FILE_TAG, tag_name=EXECUTOR_FILE_TAG,
file_name=EXECUTOR_FILE_NAME, file_name=EXECUTOR_FILE_NAME,
@@ -168,7 +166,7 @@ metas:
playground_content = self.extract_content_from_result(playground_content_raw, 'app.py', match_single_block=True) playground_content = self.extract_content_from_result(playground_content_raw, 'app.py', match_single_block=True)
persist_file(playground_content, os.path.join(microservice_path, 'app.py')) persist_file(playground_content, os.path.join(microservice_path, 'app.py'))
def debug_microservice(self, path, microservice_name, num_approach, packages, description, test): def debug_microservice(self, path, microservice_name, num_approach, packages):
for i in range(1, MAX_DEBUGGING_ITERATIONS): for i in range(1, MAX_DEBUGGING_ITERATIONS):
print('Debugging iteration', i) print('Debugging iteration', i)
print('Trying to build the microservice. Might take a while...') print('Trying to build the microservice. Might take a while...')
@@ -178,8 +176,7 @@ metas:
error = process_error_message(log_hubble) error = process_error_message(log_hubble)
if error: if error:
print('An error occurred during the build process. Feeding the error back to the assistent...') print('An error occurred during the build process. Feeding the error back to the assistent...')
self.do_debug_iteration(description, error, next_microservice_path, self.do_debug_iteration(error, next_microservice_path, previous_microservice_path)
previous_microservice_path, test)
if i == MAX_DEBUGGING_ITERATIONS - 1: if i == MAX_DEBUGGING_ITERATIONS - 1:
raise self.MaxDebugTimeReachedException('Could not debug the microservice.') raise self.MaxDebugTimeReachedException('Could not debug the microservice.')
else: else:
@@ -188,8 +185,7 @@ metas:
return get_microservice_path(path, microservice_name, packages, num_approach, i) return get_microservice_path(path, microservice_name, packages, num_approach, i)
def do_debug_iteration(self, description, error, next_microservice_path, previous_microservice_path, def do_debug_iteration(self, error, next_microservice_path, previous_microservice_path):
test):
os.makedirs(next_microservice_path) os.makedirs(next_microservice_path)
file_name_to_content = get_all_microservice_files_with_content(previous_microservice_path) file_name_to_content = get_all_microservice_files_with_content(previous_microservice_path)
@@ -201,11 +197,11 @@ metas:
key in ['requirements.txt', 'Dockerfile'] key in ['requirements.txt', 'Dockerfile']
}) })
user_query = template_solve_dependency_issue.format( user_query = template_solve_dependency_issue.format(
description=description, summarized_error=summarized_error, all_files_string=all_files_string, description=self.task_description, summarized_error=summarized_error, all_files_string=all_files_string,
) )
else: else:
user_query = template_solve_code_issue.format( user_query = template_solve_code_issue.format(
description=description, summarized_error=summarized_error, all_files_string=self.files_to_string(file_name_to_content), description=self.task_description, summarized_error=summarized_error, all_files_string=self.files_to_string(file_name_to_content),
) )
conversation = self.gpt_session.get_conversation() conversation = self.gpt_session.get_conversation()
returned_files_raw = conversation.chat(user_query) returned_files_raw = conversation.chat(user_query)
@@ -236,11 +232,11 @@ metas:
name = self.extract_content_from_result(name_raw, 'name.txt') name = self.extract_content_from_result(name_raw, 'name.txt')
return name return name
def get_possible_packages(self, description): def get_possible_packages(self):
print_colored('', '############# What packages to use? #############', 'blue') print_colored('', '############# What packages to use? #############', 'blue')
conversation = self.gpt_session.get_conversation() conversation = self.gpt_session.get_conversation()
packages_raw = conversation.chat( packages_raw = conversation.chat(
template_generate_possible_packages.format(description=description) template_generate_possible_packages.format(description=self.task_description)
) )
packages_csv_string = self.extract_content_from_result(packages_raw, 'packages.csv') packages_csv_string = self.extract_content_from_result(packages_raw, 'packages.csv')
packages_list = [[pkg.strip() for pkg in packages_string.split(',')] for packages_string in packages_csv_string.split('\n')] packages_list = [[pkg.strip() for pkg in packages_string.split(',')] for packages_string in packages_csv_string.split('\n')]
@@ -250,17 +246,15 @@ metas:
def generate(self, microservice_path): def generate(self, microservice_path):
generated_name = self.generate_microservice_name(self.task_description) generated_name = self.generate_microservice_name(self.task_description)
microservice_name = f'{generated_name}{random.randint(0, 10_000_000)}' microservice_name = f'{generated_name}{random.randint(0, 10_000_000)}'
packages_list = self.get_possible_packages(description) packages_list = self.get_possible_packages()
packages_list = [ packages_list = [
packages for packages in packages_list if len(set(packages).intersection(set(PROBLEMATIC_PACKAGES))) == 0 packages for packages in packages_list if len(set(packages).intersection(set(PROBLEMATIC_PACKAGES))) == 0
] ]
for num_approach, packages in enumerate(packages_list): for num_approach, packages in enumerate(packages_list):
try: try:
self.generate_microservice( self.generate_microservice(microservice_path, microservice_name, packages, num_approach)
self.task_description, self.test_description, microservice_path, microservice_name, packages, num_approach
)
final_version_path = self.debug_microservice( final_version_path = self.debug_microservice(
microservice_path, microservice_name, num_approach, packages, description, test microservice_path, microservice_name, num_approach, packages
) )
self.generate_playground(microservice_name, final_version_path) self.generate_playground(microservice_name, final_version_path)
except self.MaxDebugTimeReachedException: except self.MaxDebugTimeReachedException:
@@ -280,11 +274,5 @@ gptdeploy deploy --path {microservice_path}
def summarize_error(self, error): def summarize_error(self, error):
conversation = self.gpt_session.get_conversation([]) conversation = self.gpt_session.get_conversation([])
user_query = f''' error_summary = conversation.chat(template_summarize_error.format(error=error))
Here is an error message I encountered during the docker build process:
"{error}"
Your task is to summarize the error message as compact and informative as possible while maintaining all information necessary to debug the core issue.
Warnings are not worth mentioning.
'''
error_summary = conversation.query(user_query)
return error_summary return error_summary

View File

@@ -1,4 +1,5 @@
from src.constants import FLOW_URL_PLACEHOLDER from src.constants import FLOW_URL_PLACEHOLDER
from src.options.generate.templates import not_allowed_docker_string, not_allowed_executor_string
executor_example = '''Using the Jina framework, users can define executors. executor_example = '''Using the Jina framework, users can define executors.
Here is an example of how an executor can be defined. It always starts with a comment: Here is an example of how an executor can be defined. It always starts with a comment:
@@ -83,4 +84,4 @@ and the following test scenario:
{test_description} {test_description}
``` ```
You must obey the following rules:''' + f'\n{not_allowed_executor}\n{not_allowed_docker}' You must obey the following rules:''' + f'\n{not_allowed_executor_string}\n{not_allowed_docker_string}'

View File

@@ -57,7 +57,8 @@ b) has a stable api among different versions
c) does not have system requirements c) does not have system requirements
d) can solve the task when running in a docker container d) can solve the task when running in a docker container
e) the implementation of the core problem using the package would obey the following rules: e) the implementation of the core problem using the package would obey the following rules:
''' + not_allowed_executor_string() + ''' ''' + not_allowed_executor_string + '''
When answering, just write "yes" or "no". When answering, just write "yes" or "no".
5. Output the most suitable 5 python packages starting with the best one. 5. Output the most suitable 5 python packages starting with the best one.
@@ -66,11 +67,11 @@ If the package is mentioned in the description, then it is automatically the bes
The output must be a list of lists wrapped into ``` and starting with **packages.csv** like this: The output must be a list of lists wrapped into ``` and starting with **packages.csv** like this:
**packages.csv** **packages.csv**
``` ```
package1 package1a, package1b ...
package2 package2a, package2b, package2c
package3 package3a ...
package4 package4a ...
package5 package5a ...
... ...
``` ```
''') ''')
@@ -90,7 +91,7 @@ template_generate_executor = PromptTemplate.from_template(
Write the executor called '{microservice_name}'. The name is very important to keep. Write the executor called '{microservice_name}'. The name is very important to keep.
It matches the following description: '{microservice_description}'. It matches the following description: '{microservice_description}'.
It will be tested with the following scenario: '{test}'. It will be tested with the following scenario: '{test}'.
For the implementation use the following package: '{package}'. For the implementation use the following package: '{packages}'.
Obey the following rules: Obey the following rules:
Have in mind that d.uri is never a path to a local file. It is always a url. Have in mind that d.uri is never a path to a local file. It is always a url.
@@ -156,6 +157,14 @@ The Dockerfile runs the test during the build process.
) )
template_summarize_error = PromptTemplate.from_template(
'''Here is an error message I encountered during the docker build process:
"{error}"
Your task is to summarize the error message as compact and informative as possible while maintaining all information necessary to debug the core issue.
Warnings are not worth mentioning.'''
)
template_is_dependency_issue = PromptTemplate.from_template( template_is_dependency_issue = PromptTemplate.from_template(
'''Your task is to assist in identifying the root cause of a Docker build error for a python application. '''Your task is to assist in identifying the root cause of a Docker build error for a python application.
The error message is as follows: The error message is as follows:
@@ -172,15 +181,13 @@ Is this a dependency installation failure? Answer with "yes" or "no".'''
template_solve_dependency_issue = PromptTemplate.from_template( template_solve_dependency_issue = PromptTemplate.from_template(
'''Your task is to provide guidance on how to solve an error that occurred during the Docker build process. '''Your task is to provide guidance on how to solve an error that occurred during the Docker build process.
The error message is: Here is the summary of the error that occurred:
**microservice.log** {summarized_error}
```
{error}
```
To solve this error, you should: To solve this error, you should:
1. Identify the type of error by examining the stack trace. 1. Suggest 3 to 5 possible solutions on how to solve it. You have no access to the documentation of the package.
2. Suggest how to solve it. 2. Decide for the best solution and explain it in detail.
3. Your suggestion must include the files that need to be changed, but not files that don't need to be changed. 3. Write down the files that need to be changed, but not files that don't need to be changed.
For files that need to be changed, you must provide the complete file with the exact same syntax to wrap the code. For files that need to be changed, you must provide the complete file with the exact same syntax to wrap the code.
Obey the following rules: Obey the following rules:
''' + not_allowed_docker_string() + ''' ''' + not_allowed_docker_string() + '''
@@ -188,6 +195,22 @@ Obey the following rules:
You are given the following files: You are given the following files:
{all_files_string} {all_files_string}
Output all the files that need change.
Don't output files that don't need change. If you output a file, then write the
complete file. Use the exact following syntax to wrap the code:
**...**
```
...code...
```
Example:
**requirements.txt**
```
jina==2.0.0
```
''' '''
) )
@@ -205,19 +228,31 @@ Here are all the files I use:
{all_files_string} {all_files_string}
This is the error I encounter currently during the docker build process: Here is the summary of the error that occurred:
{error} {summarized_error}
Look at the stack trace of the current error. First, think about what kind of error is this? To solve this error, you should:
Then think about possible reasons which might have caused it. Then suggest how to 1. Suggest 3 to 5 possible solutions on how to solve it. You have no access to the documentation of the package.
solve it. Output all the files that need change. 2. Decide for the best solution and explain it in detail.
3. Write down the files that need to be changed, but not files that don't need to be changed.
Obey the following rules:
''' + f'{not_allowed_executor_string}\n{not_allowed_docker_string}' + '''
Output all the files that need change.
Don't output files that don't need change. If you output a file, then write the Don't output files that don't need change. If you output a file, then write the
complete file. Use the exact same syntax to wrap the code: complete file. Use the exact following syntax to wrap the code:
**...** **...**
```... ```...
...code... ...code...
``` ```
'''
Example:
**microservice.py**
```python
print('hello world')
```'''
) )
@@ -237,7 +272,7 @@ response = client.post('/', inputs=DocumentArray([d])) # always use '/'
print(response[0].text) # can also be blob in case of image/audio..., this should be visualized in the streamlit app print(response[0].text) # can also be blob in case of image/audio..., this should be visualized in the streamlit app
``` ```
Note that the response will always be in response[0].text Note that the response will always be in response[0].text
You must provide the complete file with the exact same syntax to wrap the code. You must provide the complete app.py file with the exact same syntax to wrap the code.
The playground (app.py) must read the host from sys.argv because it will be started with a custom host: streamlit run app.py -- --host grpc://... The playground (app.py) must read the host from sys.argv because it will be started with a custom host: streamlit run app.py -- --host grpc://...
The playground (app.py) must not let the user configure the host on the ui. The playground (app.py) must not let the user configure the host on the ui.
''' '''