refactor: playground more stable generation

This commit is contained in:
Florian Hönicke
2023-05-22 11:48:28 +02:00
parent 458d5eb1a4
commit 5792225ea1
5 changed files with 60 additions and 69 deletions

View File

@@ -27,7 +27,9 @@ FILE_AND_TAG_PAIRS = [
] ]
INDICATOR_TO_IMPORT_STATEMENT = { INDICATOR_TO_IMPORT_STATEMENT = {
'io.BytesIO': 'import io',
'BytesIO': 'from io import BytesIO', 'BytesIO': 'from io import BytesIO',
'base64': 'import base64',
} }
FLOW_URL_PLACEHOLDER = 'jcloud.jina.ai' FLOW_URL_PLACEHOLDER = 'jcloud.jina.ai'

View File

@@ -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_output_schema_prompt = '''{context_string}
Generate the lean response json schema for the Microservice. 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} 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. Write an updated microservice description by incorporating information about the request and response parameters in a concise way without losing any information.

View File

@@ -250,7 +250,7 @@ metas:
line.replace('{{APT_GET_PACKAGES}}', '').replace('{{DOCKER_BASE_IMAGE_VERSION}}', DOCKER_BASE_IMAGE_VERSION) line.replace('{{APT_GET_PACKAGES}}', '').replace('{{DOCKER_BASE_IMAGE_VERSION}}', DOCKER_BASE_IMAGE_VERSION)
for line in docker_file_template_lines 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')) persist_file(docker_file_content, os.path.join(self.cur_microservice_path, 'Dockerfile'))
self.write_config_yml(self.microservice_name, self.cur_microservice_path) 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): 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():
for file_name, file_content in content_dict.items(): file_content = self.add_missing_imports_for_file(file_content)
if indicator in file_content and import_statement not in file_content: content_dict[file_name] = file_content
content_dict[file_name] = f'{import_statement}\n{file_content}'
return content_dict 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 @staticmethod
def read_docker_template(): def read_docker_template():
@@ -295,12 +299,15 @@ pytest
def generate_playground(self): def generate_playground(self):
print_colored('', '\n\n############# Playground #############', 'blue') 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) file_name_to_content = get_all_microservice_files_with_content(self.cur_microservice_path)
conversation = self.gpt_session.get_conversation() conversation = self.gpt_session.get_conversation()
conversation.chat( conversation.chat(
template_generate_playground.format( 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, microservice_name=self.microservice_name,
playground_template=playground_template,
) )
) )
playground_content_raw = conversation.chat( playground_content_raw = conversation.chat(
@@ -316,6 +323,7 @@ pytest
playground_content = self.extract_content_from_result( playground_content = self.extract_content_from_result(
content_raw, 'app.py', match_single_block=True 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') gateway_path = os.path.join(self.cur_microservice_path, 'gateway')
shutil.copytree(os.path.join(os.path.dirname(__file__), 'static_files', 'gateway'), gateway_path) shutil.copytree(os.path.join(os.path.dirname(__file__), 'static_files', 'gateway'), gateway_path)

View File

@@ -1,53 +1,53 @@
import json import json
import os import os
import base64
import streamlit as st import streamlit as st
from jina import Client, Document, DocumentArray from jina import Client, Document, DocumentArray
import io
st.set_page_config( st.set_page_config(
page_title="<page title here>", page_title="<page title here>",
page_icon="<page icon here>", page_icon="<page icon here>",
layout="<page layout here>", layout="centered",
initial_sidebar_state="<sidebar state here>", initial_sidebar_state="auto",
) )
st.title("<thematic emoji here> <header title here>") st.title("<thematic emoji here> <header title here>")
st.markdown( st.markdown(
"<10 word description here>" "<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.subheader("<a unique thematic emoji here> <sub header title here>") # only if input parameters are needed
st.header("<another thematic emoji here> Input Parameters") # only if input parameters are needed
with st.form(key="input_form"): with st.form(key="input_form"):
<input parameter definition here> # <input parameter definition here>
input_json_dict = {} #
input_data = { input_json_dict_string = json.dumps(input_json_dict)
<input parameters here> submitted = st.form_submit_button("<submit button text>")
}
input_json = json.dumps(input_data)
# Process input and call microservice # Process input and call microservice
if submit_button: if submitted:
with st.spinner("Generating collage..."): with st.spinner("<spinner text here>..."):
client = Client(host="http://localhost:8080") client = Client(host="http://localhost:8080")
d = Document(text=input_json) d = Document(text=input_json_dict_string)
response = client.post("/", inputs=DocumentArray([d])) response = client.post("/", inputs=DocumentArray([d]))
output_data = json.loads(response[0].text) output_data = json.loads(response[0].text)
<visualization of results> # <visualization of results here>
# Display curl command # Display curl command
deployment_id = os.environ.get("K8S_NAMESPACE_NAME", "") deployment_id = os.environ.get("K8S_NAMESPACE_NAME", "")
host = ( api_endpoint = (
f"https://dev-gpt-{deployment_id.split('-')[1]}.wolf.jina.ai/post" f"https://dev-gpt-{deployment_id.split('-')[1]}.wolf.jina.ai/post"
if deployment_id if deployment_id
else "http://localhost:8080/post" else "http://localhost:8080/post"
) )
with st.expander("See curl command"): 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:") 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( 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", language="bash",
) )

View File

@@ -132,9 +132,10 @@ def template_generate_function_constructor(is_using_gpt_3_5_turbo, is_using_goog
general_guidelines_string + f''' general_guidelines_string + f'''
Write a python function which receives as \ Write a python function which receives as \
input json string (that can be parsed with the python function json.loads) and \ input json dictionary 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). \ outputs a json dictionary string (that can be parsed with the python function json.loads). \
The function is called 'func'. 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}}'. The function must fulfill the following description: '{{microservice_description}}'.
It will be tested with the following scenario: '{{test_description}}'. It will be tested with the following scenario: '{{test_description}}'.
For the implementation use the following package(s): '{{packages}}'. For the implementation use the following package(s): '{{packages}}'.
@@ -433,13 +434,12 @@ Use the exact following syntax to wrap the code:
``` ```
Example: Example:
**implementation.py** **implementation.py**
```python ```python
import json import json
def func(json_input: str) -> str: def func(input_json_dict_string: str) -> str:
return json_input['img_base64'] return json.dumps('output_param1': input_json_dict_string['img_base64'])
```''' ```'''
) )
@@ -449,50 +449,30 @@ template_generate_playground = PromptTemplate.from_template(
{code_files_wrapped} {code_files_wrapped}
Create a playground for the executor {microservice_name} using streamlit. 1. Write down the json request model required by microservice.py.
The playground must look like it was made by a professional designer. 2. Generate a playground for the microservice {microservice_name} using the following streamlit template by replacing all the placeholders (<...>) with the correct values:
All the ui elements are well thought out to make them visually appealing and easy to use. **app_template.py**
Don't mention the word Playground in the title. ```python
The playground contains many emojis that fit the theme of the playground and has an emoji as favicon. {playground_template}
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:
``` ```
from jina import Client, Document, DocumentArray Note: Don't mention the word Playground in the title.
client = Client(host='http://localhost:8080') Most importantly: You must generate the complete app.py file using the following syntax to wrap the code:
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:
**app.py** **app.py**
```python ```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( 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. 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.
Be very hesitant to change the code. Only make a change if you are sure that it is necessary. 2. Explain why. (5 words per item)
3. Think if all the changes are required
Output only {file_name_purpose} 4. decide for the changes you want to make, but you are not allowed disregard the instructions in the previous message.
Write the whole content of {file_name_purpose} - even if you decided to change only a small thing or even nothing. 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 + ''' ''' + '\n' + template_code_wrapping_string + '''
Remember: Remember: