diff --git a/dev_gpt/constants.py b/dev_gpt/constants.py index 20181c8..facfeaf 100644 --- a/dev_gpt/constants.py +++ b/dev_gpt/constants.py @@ -27,7 +27,9 @@ FILE_AND_TAG_PAIRS = [ ] INDICATOR_TO_IMPORT_STATEMENT = { + 'io.BytesIO': 'import io', 'BytesIO': 'from io import BytesIO', + 'base64': 'import base64', } FLOW_URL_PLACEHOLDER = 'jcloud.jina.ai' diff --git a/dev_gpt/options/generate/chains/auto_refine_description.py b/dev_gpt/options/generate/chains/auto_refine_description.py index aef8e08..085295a 100644 --- a/dev_gpt/options/generate/chains/auto_refine_description.py +++ b/dev_gpt/options/generate/chains/auto_refine_description.py @@ -49,7 +49,8 @@ Note: If you are not sure about the details, then come up with the minimal numbe 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.''' +Note: If you are not sure about the details, then come up with the minimal number of parameters possible. +Note: If you can decide to return files as URLs or as base64 encoded strings, then choose the base64 encoded strings.''' 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. diff --git a/dev_gpt/options/generate/generator.py b/dev_gpt/options/generate/generator.py index 700b7d9..5bd0f69 100644 --- a/dev_gpt/options/generate/generator.py +++ b/dev_gpt/options/generate/generator.py @@ -250,7 +250,7 @@ metas: line.replace('{{APT_GET_PACKAGES}}', '').replace('{{DOCKER_BASE_IMAGE_VERSION}}', DOCKER_BASE_IMAGE_VERSION) for line in docker_file_template_lines ] - docker_file_content = '\n'.join(docker_file_template_lines) + docker_file_content = ''.join(docker_file_template_lines) persist_file(docker_file_content, os.path.join(self.cur_microservice_path, 'Dockerfile')) self.write_config_yml(self.microservice_name, self.cur_microservice_path) @@ -259,12 +259,16 @@ metas: def add_missing_imports_post_process_fn(self, content_dict: dict): - for indicator, import_statement in INDICATOR_TO_IMPORT_STATEMENT.items(): - for file_name, file_content in content_dict.items(): - if indicator in file_content and import_statement not in file_content: - content_dict[file_name] = f'{import_statement}\n{file_content}' + for file_name, file_content in content_dict.items(): + file_content = self.add_missing_imports_for_file(file_content) + content_dict[file_name] = file_content return content_dict + def add_missing_imports_for_file(self, file_content): + for indicator, import_statement in INDICATOR_TO_IMPORT_STATEMENT.items(): + if indicator in file_content and import_statement not in file_content: + file_content = f'{import_statement}\n{file_content}' + return file_content @staticmethod def read_docker_template(): @@ -295,12 +299,15 @@ pytest def generate_playground(self): print_colored('', '\n\n############# Playground #############', 'blue') + with open(os.path.join(os.path.dirname(__file__), 'static_files', 'gateway', 'app_template.py'), 'r', encoding='utf-8') as f: + playground_template = f.read() file_name_to_content = get_all_microservice_files_with_content(self.cur_microservice_path) conversation = self.gpt_session.get_conversation() conversation.chat( template_generate_playground.format( - code_files_wrapped=self.files_to_string(file_name_to_content, ['test_microservice.py']), + code_files_wrapped=self.files_to_string(file_name_to_content, ['test_microservice.py', 'microservice.py']), microservice_name=self.microservice_name, + playground_template=playground_template, ) ) playground_content_raw = conversation.chat( @@ -316,6 +323,7 @@ pytest playground_content = self.extract_content_from_result( content_raw, 'app.py', match_single_block=True ) + playground_content = self.add_missing_imports_for_file(playground_content) gateway_path = os.path.join(self.cur_microservice_path, 'gateway') shutil.copytree(os.path.join(os.path.dirname(__file__), 'static_files', 'gateway'), gateway_path) diff --git a/dev_gpt/options/generate/static_files/gateway/app-template b/dev_gpt/options/generate/static_files/gateway/app_template.py similarity index 51% rename from dev_gpt/options/generate/static_files/gateway/app-template rename to dev_gpt/options/generate/static_files/gateway/app_template.py index cda8597..a9ec3cd 100644 --- a/dev_gpt/options/generate/static_files/gateway/app-template +++ b/dev_gpt/options/generate/static_files/gateway/app_template.py @@ -1,53 +1,53 @@ import json import os -import base64 + import streamlit as st from jina import Client, Document, DocumentArray +import io st.set_page_config( page_title="", page_icon="", - layout="", - initial_sidebar_state="", + layout="centered", + initial_sidebar_state="auto", ) st.title("
") st.markdown( "<10 word description here>" - "To deploy your own microservice, click [here](https://github.com/jina-ai/dev-gpt)." + "To generate and deploy your own microservice, click [here](https://github.com/jina-ai/dev-gpt)." ) - -st.header(" Input Parameters") # only if input parameters are needed +st.subheader(" ") # only if input parameters are needed with st.form(key="input_form"): - + # + input_json_dict = {} # -input_data = { - -} -input_json = json.dumps(input_data) + input_json_dict_string = json.dumps(input_json_dict) + submitted = st.form_submit_button("") # Process input and call microservice -if submit_button: - with st.spinner("Generating collage..."): - - +if submitted: + with st.spinner("..."): client = Client(host="http://localhost:8080") - d = Document(text=input_json) + d = Document(text=input_json_dict_string) response = client.post("/", inputs=DocumentArray([d])) output_data = json.loads(response[0].text) - + # # Display curl command deployment_id = os.environ.get("K8S_NAMESPACE_NAME", "") -host = ( +api_endpoint = ( f"https://dev-gpt-{deployment_id.split('-')[1]}.wolf.jina.ai/post" if deployment_id else "http://localhost:8080/post" ) + with st.expander("See curl command"): st.markdown("You can use the following curl command to send a request to the microservice from the command line:") + escaped_input_json_dict_string = input_json_dict_string.replace('"', '\\"') + st.code( - f'curl -X "POST" "{host}" -H "accept: application/json" -H "Content-Type: application/json" -d \'{{"data": [{{"text": "{input_json}"}}]}}\'', + f'curl -X "POST" "{api_endpoint}" -H "accept: application/json" -H "Content-Type: application/json" -d \'{{"data": [{{"text": "{escaped_input_json_dict_string}"}}]}}\'', language="bash", - ) \ No newline at end of file + ) diff --git a/dev_gpt/options/generate/templates_user.py b/dev_gpt/options/generate/templates_user.py index ee19cbf..1ae01a5 100644 --- a/dev_gpt/options/generate/templates_user.py +++ b/dev_gpt/options/generate/templates_user.py @@ -132,9 +132,10 @@ def template_generate_function_constructor(is_using_gpt_3_5_turbo, is_using_goog general_guidelines_string + f''' Write a python function which receives as \ -input json string (that can be parsed with the python function json.loads) and \ -outputs a json string (that can be parsed with the python function json.loads). \ -The function is called 'func'. +input json dictionary string (that can be parsed with the python function json.loads) and \ +outputs a json dictionary string (that can be parsed with the python function json.loads). \ +The function is called 'func' and has the following signature: +def func(input_json_dict_string: str) -> str: The function must fulfill the following description: '{{microservice_description}}'. It will be tested with the following scenario: '{{test_description}}'. For the implementation use the following package(s): '{{packages}}'. @@ -433,13 +434,12 @@ Use the exact following syntax to wrap the code: ``` Example: - **implementation.py** ```python import json -def func(json_input: str) -> str: - return json_input['img_base64'] +def func(input_json_dict_string: str) -> str: + return json.dumps('output_param1': input_json_dict_string['img_base64']) ```''' ) @@ -449,50 +449,30 @@ template_generate_playground = PromptTemplate.from_template( {code_files_wrapped} -Create a playground for the executor {microservice_name} using streamlit. -The playground must look like it was made by a professional designer. -All the ui elements are well thought out to make them visually appealing and easy to use. -Don't mention the word Playground in the title. -The playground contains many emojis that fit the theme of the playground and has an emoji as favicon. -The playground encourages the user to deploy their own microservice by clicking on this link: https://github.com/jina-ai/dev-gpt -The playground uses the following code to send a request to the microservice: +1. Write down the json request model required by microservice.py. +2. Generate a playground for the microservice {microservice_name} using the following streamlit template by replacing all the placeholders (<...>) with the correct values: +**app_template.py** +```python +{playground_template} ``` -from jina import Client, Document, DocumentArray -client = Client(host='http://localhost:8080') -d = Document(text=json.dumps(INPUT_DICTIONARY)) # fill-in dictionary which takes input -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 -``` -Note that the response will always be in response[0].text -The playground displays a code block containing the microservice specific curl code that can be used to send the request to the microservice. -While the exact payload in the curl might change, the host and deployment ID always stay the same. Example: -``` -deployment_id = os.environ.get("K8S_NAMESPACE_NAME", "") -host = f'https://dev-gpt-{{deployment_id.split("-")[1]}}.wolf.jina.ai/post' if deployment_id else "http://localhost:8080/post" -with st.expander("See curl command"): - st.code( - f'curl -X \\'POST\\' \\'host\\' -H \\'accept: application/json\\' -H \\'Content-Type: application/json\\' -d \\'{{{{"data": [{{{{"text": "hello, world!"}}}}]}}}}\\'', - language='bash' - ) -``` -You must provide the complete app.py file using the following syntax to wrap the code: +Note: Don't mention the word Playground in the title. +Most importantly: You must generate the complete app.py file using the following syntax to wrap the code: **app.py** ```python ... -``` -The playground (app.py) must always use the host on http://localhost:8080 and must not let the user configure the host on the UI. -The playground (app.py) must not import the executor. -''' +```''' ) template_chain_of_thought = PromptTemplate.from_template( - '''First, write down an extensive list of obvious and non-obvious observations about {file_name_purpose} that could need an adjustment. Explain why. -Think if all the changes are required and finally decide for the changes you want to make, but you are not allowed disregard the instructions in the previous message. -Be very hesitant to change the code. Only make a change if you are sure that it is necessary. - -Output only {file_name_purpose} -Write the whole content of {file_name_purpose} - even if you decided to change only a small thing or even nothing. + '''\ +1. write down an extensive list (5 words per item) of obvious and non-obvious observations about {file_name_purpose} that could need an adjustment. +2. Explain why. (5 words per item) +3. Think if all the changes are required +4. decide for the changes you want to make, but you are not allowed disregard the instructions in the previous message. +5. Write the whole content of {file_name_purpose} - even if you decided to change only a small thing or even nothing. +Note: Be very hesitant to change the code. Only make a change if you are sure that it is necessary. +Note: Output only {file_name_purpose} ''' + '\n' + template_code_wrapping_string + ''' Remember: