From 691f7f72574c3cd631ba343dd820e3d426109787 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Wed, 15 Nov 2023 17:45:49 +0800 Subject: [PATCH 01/35] Add bugbash sample flows --- .../flows/chat/chat-with-image/chat.jinja2 | 12 ++++++ .../flows/chat/chat-with-image/flow.dag.yaml | 29 +++++++++++++ .../flows/chat/chat-with-image/flow.meta.yaml | 9 ++++ .../chat/chat-with-image/requirements.txt | 0 .../evaluation/eval-description/aggregate.py | 10 +++++ .../evaluation/eval-description/data/img2.jpg | Bin 0 -> 5918 bytes .../evaluate_description_matchness.jinja2 | 10 +++++ .../evaluation/eval-description/flow.dag.yaml | 40 ++++++++++++++++++ .../eval-description/flow.meta.yaml | 10 +++++ .../eval-description/line_process.py | 17 ++++++++ .../eval-description/requirements.txt | 0 .../evaluation/eval-description/samples.json | 6 +++ .../standard/describe-image/data/img1.jpg | Bin 0 -> 13290 bytes .../standard/describe-image/data/img2.jpg | Bin 0 -> 5918 bytes .../standard/describe-image/data/input.jsonl | 2 + .../standard/describe-image/flow.dag.yaml | 34 +++++++++++++++ .../standard/describe-image/passthrough.py | 7 +++ .../describe-image/question_on_image.jinja2 | 6 +++ 18 files changed, 192 insertions(+) create mode 100644 examples/flows/chat/chat-with-image/chat.jinja2 create mode 100644 examples/flows/chat/chat-with-image/flow.dag.yaml create mode 100644 examples/flows/chat/chat-with-image/flow.meta.yaml create mode 100644 examples/flows/chat/chat-with-image/requirements.txt create mode 100644 examples/flows/evaluation/eval-description/aggregate.py create mode 100644 examples/flows/evaluation/eval-description/data/img2.jpg create mode 100644 examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 create mode 100644 examples/flows/evaluation/eval-description/flow.dag.yaml create mode 100644 examples/flows/evaluation/eval-description/flow.meta.yaml create mode 100644 examples/flows/evaluation/eval-description/line_process.py create mode 100644 examples/flows/evaluation/eval-description/requirements.txt create mode 100644 examples/flows/evaluation/eval-description/samples.json create mode 100644 examples/flows/standard/describe-image/data/img1.jpg create mode 100644 examples/flows/standard/describe-image/data/img2.jpg create mode 100644 examples/flows/standard/describe-image/data/input.jsonl create mode 100644 examples/flows/standard/describe-image/flow.dag.yaml create mode 100644 examples/flows/standard/describe-image/passthrough.py create mode 100644 examples/flows/standard/describe-image/question_on_image.jinja2 diff --git a/examples/flows/chat/chat-with-image/chat.jinja2 b/examples/flows/chat/chat-with-image/chat.jinja2 new file mode 100644 index 00000000000..96bfb60a45b --- /dev/null +++ b/examples/flows/chat/chat-with-image/chat.jinja2 @@ -0,0 +1,12 @@ +# system: +You are a helpful assistant. + +{% for item in chat_history %} +# user: +{{item.inputs.question}} +# assistant: +{{item.outputs.answer}} +{% endfor %} + +# user: +{{question}} \ No newline at end of file diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml new file mode 100644 index 00000000000..41deff4111b --- /dev/null +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -0,0 +1,29 @@ +id: template_chat_flow +name: Template Chat Flow +environment: + python_requirements_txt: requirements.txt +inputs: + chat_history: + type: list + is_chat_history: true + question: + type: list + is_chat_input: true +outputs: + answer: + type: string + reference: ${chat.output} + is_chat_output: true +nodes: +- name: chat + type: custom_llm + source: + type: package_with_prompt + tool: promptflow.tools.openai_gpt4v.OpenAI.chat + path: chat.jinja2 + inputs: + connection: openai-connection + model: gpt-4-vision-preview + max_tokens: 200 + chat_history: ${inputs.chat_history} + question: ${inputs.question} diff --git a/examples/flows/chat/chat-with-image/flow.meta.yaml b/examples/flows/chat/chat-with-image/flow.meta.yaml new file mode 100644 index 00000000000..9b440bbc9b4 --- /dev/null +++ b/examples/flows/chat/chat-with-image/flow.meta.yaml @@ -0,0 +1,9 @@ +$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json +name: template_chat_flow +display_name: Template Chat Flow +type: chat +path: ./flow.dag.yaml +description: Template Chat Flow +properties: + promptflow.stage: prod + promptflow.section: template diff --git a/examples/flows/chat/chat-with-image/requirements.txt b/examples/flows/chat/chat-with-image/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/flows/evaluation/eval-description/aggregate.py b/examples/flows/evaluation/eval-description/aggregate.py new file mode 100644 index 00000000000..bf9d10146a0 --- /dev/null +++ b/examples/flows/evaluation/eval-description/aggregate.py @@ -0,0 +1,10 @@ +from typing import List +from promptflow import tool, log_metric + + +@tool +def calculate_accuracy(grades: List[str]): + accuracy = round((grades.count("Yes") / len(grades)), 2) + log_metric("accuracy", accuracy) + + return accuracy diff --git a/examples/flows/evaluation/eval-description/data/img2.jpg b/examples/flows/evaluation/eval-description/data/img2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0fad50cc349ea5cec09a519e9f06b10e3b00ca4 GIT binary patch literal 5918 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 PX$`xXgrf@S?!Ny&liS2r literal 0 HcmV?d00001 diff --git a/examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 b/examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 new file mode 100644 index 00000000000..47e41511236 --- /dev/null +++ b/examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 @@ -0,0 +1,10 @@ +# system: +As an AI assistant, your task involves interpreting images and responding to questions about the image. +Remember to provide accurate answers based on the information present in the image. + +# user: +Is the answer to the question about the image correct? +Question: {{question}} +Answer: {{answer}} +Image: ![image]({{image_input}}) +Only answer "Yes" or "No", no extra words or punctuation. \ No newline at end of file diff --git a/examples/flows/evaluation/eval-description/flow.dag.yaml b/examples/flows/evaluation/eval-description/flow.dag.yaml new file mode 100644 index 00000000000..15228104c0a --- /dev/null +++ b/examples/flows/evaluation/eval-description/flow.dag.yaml @@ -0,0 +1,40 @@ +id: template_eval_flow +name: Template Evaluation Flow +environment: + python_requirements_txt: requirements.txt +inputs: + image: + type: image + default: data/img2.jpg + qustion: + type: string + default: What's in the image? + answer: + type: string + default: A yellow bird +outputs: + results: + type: string + reference: ${evaluate_description_matchness.output} +nodes: +- name: evaluate_description_matchness + type: custom_llm + source: + type: package_with_prompt + tool: promptflow.tools.openai_gpt4v.OpenAI.chat + path: evaluate_description_matchness.jinja2 + inputs: + connection: openai-connection + model: gpt-4-vision-preview + max_tokens: 200 + image_input: ${inputs.image} + question: ${inputs.qustion} + answer: ${inputs.answer} +- name: aggregate + type: python + source: + type: code + path: aggregate.py + inputs: + grades: ${evaluate_description_matchness.output} + aggregation: true diff --git a/examples/flows/evaluation/eval-description/flow.meta.yaml b/examples/flows/evaluation/eval-description/flow.meta.yaml new file mode 100644 index 00000000000..b88024def92 --- /dev/null +++ b/examples/flows/evaluation/eval-description/flow.meta.yaml @@ -0,0 +1,10 @@ +$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json +name: template_eval_flow +display_name: Template Eval Flow +type: evaluate +path: ./flow.dag.yaml +description: Template Evaluation Flow +properties: + promptflow.stage: prod + promptflow.section: template + promptflow.batch_inputs: samples.json diff --git a/examples/flows/evaluation/eval-description/line_process.py b/examples/flows/evaluation/eval-description/line_process.py new file mode 100644 index 00000000000..736e66795bf --- /dev/null +++ b/examples/flows/evaluation/eval-description/line_process.py @@ -0,0 +1,17 @@ +from promptflow import tool + + +@tool +def line_process(groundtruth: str, prediction: str): + """ + This tool processes the prediction of a single line and returns the processed result. + + :param groundtruth: the groundtruth of a single line. + :param prediction: the prediction of a single line. + """ + + processed_result = "" + + # Add your line processing logic here + + return processed_result diff --git a/examples/flows/evaluation/eval-description/requirements.txt b/examples/flows/evaluation/eval-description/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/flows/evaluation/eval-description/samples.json b/examples/flows/evaluation/eval-description/samples.json new file mode 100644 index 00000000000..e56b5737ea1 --- /dev/null +++ b/examples/flows/evaluation/eval-description/samples.json @@ -0,0 +1,6 @@ +[ + { + "groundtruth": "Tomorrow's weather will be sunny.", + "prediction": "The weather will be sunny tomorrow." + } +] diff --git a/examples/flows/standard/describe-image/data/img1.jpg b/examples/flows/standard/describe-image/data/img1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4873960fa360ffaa25b6481ba33f34bf0fbcc3df GIT binary patch literal 13290 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 Cdp3#y literal 0 HcmV?d00001 diff --git a/examples/flows/standard/describe-image/data/img2.jpg b/examples/flows/standard/describe-image/data/img2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0fad50cc349ea5cec09a519e9f06b10e3b00ca4 GIT binary patch literal 5918 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 PX$`xXgrf@S?!Ny&liS2r literal 0 HcmV?d00001 diff --git a/examples/flows/standard/describe-image/data/input.jsonl b/examples/flows/standard/describe-image/data/input.jsonl new file mode 100644 index 00000000000..917261af56f --- /dev/null +++ b/examples/flows/standard/describe-image/data/input.jsonl @@ -0,0 +1,2 @@ +{"question": "Please describe this image:", "input_image": {"data:image/jpg;path": "img1.jpg"}} +{"question": "Please describe images:", "input_image": {"data:image/jpg;path": "img2.jpg"}} \ No newline at end of file diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml new file mode 100644 index 00000000000..3b88a7b06d3 --- /dev/null +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -0,0 +1,34 @@ +inputs: + question: + type: string + default: Please describe this image. + input_image: + type: image + default: data/img1.jpg +outputs: + answer: + type: string + reference: ${question_on_image.output} + output_image: + type: string + reference: ${passthrough.output} +nodes: +- name: question_on_image + type: custom_llm + source: + type: package_with_prompt + tool: promptflow.tools.openai_gpt4v.OpenAI.chat + path: question_on_image.jinja2 + inputs: + connection: openai-connection + question: ${inputs.question} + test_image: ${passthrough.output} + model: gpt-4-vision-preview + max_tokens: 200 +- name: passthrough + type: python + source: + type: code + path: passthrough.py + inputs: + input_image: ${inputs.input_image} diff --git a/examples/flows/standard/describe-image/passthrough.py b/examples/flows/standard/describe-image/passthrough.py new file mode 100644 index 00000000000..b094331d351 --- /dev/null +++ b/examples/flows/standard/describe-image/passthrough.py @@ -0,0 +1,7 @@ +from promptflow import tool +from promptflow.contracts.multimedia import Image + + +@tool +def passthrough(input_image: Image) -> Image: + return input_image diff --git a/examples/flows/standard/describe-image/question_on_image.jinja2 b/examples/flows/standard/describe-image/question_on_image.jinja2 new file mode 100644 index 00000000000..efabb9c712b --- /dev/null +++ b/examples/flows/standard/describe-image/question_on_image.jinja2 @@ -0,0 +1,6 @@ +# system: +You are a helpful assistant. + +# user: +{{question}} +![image]({{test_image}}) From 175466f9a987ccc5b5843cf431b2ea8cec586f04 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Wed, 15 Nov 2023 19:16:34 +0800 Subject: [PATCH 02/35] rename eval flow --- .../aggregate.py | 0 .../data/img2.jpg | Bin .../evaluate_description_matchness.jinja2 | 0 .../flow.dag.yaml | 0 .../flow.meta.yaml | 0 .../line_process.py | 0 .../requirements.txt | 0 .../samples.json | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/aggregate.py (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/data/img2.jpg (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/evaluate_description_matchness.jinja2 (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/flow.dag.yaml (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/flow.meta.yaml (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/line_process.py (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/requirements.txt (100%) rename examples/flows/evaluation/{eval-description => eval-image-description-accuracy}/samples.json (100%) diff --git a/examples/flows/evaluation/eval-description/aggregate.py b/examples/flows/evaluation/eval-image-description-accuracy/aggregate.py similarity index 100% rename from examples/flows/evaluation/eval-description/aggregate.py rename to examples/flows/evaluation/eval-image-description-accuracy/aggregate.py diff --git a/examples/flows/evaluation/eval-description/data/img2.jpg b/examples/flows/evaluation/eval-image-description-accuracy/data/img2.jpg similarity index 100% rename from examples/flows/evaluation/eval-description/data/img2.jpg rename to examples/flows/evaluation/eval-image-description-accuracy/data/img2.jpg diff --git a/examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 b/examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-description/evaluate_description_matchness.jinja2 rename to examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 diff --git a/examples/flows/evaluation/eval-description/flow.dag.yaml b/examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml similarity index 100% rename from examples/flows/evaluation/eval-description/flow.dag.yaml rename to examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml diff --git a/examples/flows/evaluation/eval-description/flow.meta.yaml b/examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml similarity index 100% rename from examples/flows/evaluation/eval-description/flow.meta.yaml rename to examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml diff --git a/examples/flows/evaluation/eval-description/line_process.py b/examples/flows/evaluation/eval-image-description-accuracy/line_process.py similarity index 100% rename from examples/flows/evaluation/eval-description/line_process.py rename to examples/flows/evaluation/eval-image-description-accuracy/line_process.py diff --git a/examples/flows/evaluation/eval-description/requirements.txt b/examples/flows/evaluation/eval-image-description-accuracy/requirements.txt similarity index 100% rename from examples/flows/evaluation/eval-description/requirements.txt rename to examples/flows/evaluation/eval-image-description-accuracy/requirements.txt diff --git a/examples/flows/evaluation/eval-description/samples.json b/examples/flows/evaluation/eval-image-description-accuracy/samples.json similarity index 100% rename from examples/flows/evaluation/eval-description/samples.json rename to examples/flows/evaluation/eval-image-description-accuracy/samples.json From 18ef49d1949bff9d97051fa5d65a016636ec8b4e Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Thu, 16 Nov 2023 10:51:46 +0800 Subject: [PATCH 03/35] Add image passthrough flow --- .../standard/image-pass-through/flow.dag.yaml | 29 ++++++++++++++++++ .../standard/image-pass-through/logo.jpg | Bin 0 -> 140150 bytes .../standard/image-pass-through/logo_2.png | Bin 0 -> 39417 bytes .../image-pass-through/pick_an_image.py | 9 ++++++ 4 files changed, 38 insertions(+) create mode 100644 examples/flows/standard/image-pass-through/flow.dag.yaml create mode 100644 examples/flows/standard/image-pass-through/logo.jpg create mode 100644 examples/flows/standard/image-pass-through/logo_2.png create mode 100644 examples/flows/standard/image-pass-through/pick_an_image.py diff --git a/examples/flows/standard/image-pass-through/flow.dag.yaml b/examples/flows/standard/image-pass-through/flow.dag.yaml new file mode 100644 index 00000000000..af3eccc8075 --- /dev/null +++ b/examples/flows/standard/image-pass-through/flow.dag.yaml @@ -0,0 +1,29 @@ +inputs: + image: + type: image + default: https://img.mp.itc.cn/upload/20160526/0c2848cb6e614b4f9345940fcba2edc7_th.jpg + is_chat_input: false +outputs: + output: + type: image + reference: ${python_node_2.output} +nodes: +- name: python_node + type: python + source: + type: code + path: pick_an_image.py + inputs: + image_1: ${inputs.image} + image_2: logo_2.png + use_variants: false +- name: python_node_2 + type: python + source: + type: code + path: pick_an_image.py + inputs: + image_1: ${python_node.output} + image_2: logo.jpg + use_variants: false +node_variants: {} diff --git a/examples/flows/standard/image-pass-through/logo.jpg b/examples/flows/standard/image-pass-through/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..155609310c8035a8fd06efa61d2cecb5d3f5eb15 GIT binary patch literal 140150 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

Ghkzv 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

9*Yk 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 fpJk&e9(IC}qIab*^{ZRf+vx(g{VaE%?S7Iu) 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 YOYA{2cI`Ia3eN3`pq0$V!)GP_8&Kr}NdN!< literal 0 HcmV?d00001 diff --git a/examples/flows/standard/image-pass-through/pick_an_image.py b/examples/flows/standard/image-pass-through/pick_an_image.py new file mode 100644 index 00000000000..1c358e83b4a --- /dev/null +++ b/examples/flows/standard/image-pass-through/pick_an_image.py @@ -0,0 +1,9 @@ +import random + +from promptflow.contracts.multimedia import Image +from promptflow import tool + + +@tool +def pick_an_image(image_1: Image, image_2: Image) -> Image: + return image_1 From 0773c7246506b91c39a10e6009c39de63ae6dc0b Mon Sep 17 00:00:00 2001 From: minggu Date: Sat, 2 Dec 2023 23:18:01 +0800 Subject: [PATCH 04/35] remove evaluation sample --- .../aggregate.py | 10 ----- .../data/img2.jpg | Bin 5918 -> 0 bytes .../evaluate_description_matchness.jinja2 | 10 ----- .../flow.dag.yaml | 40 ------------------ .../flow.meta.yaml | 10 ----- .../line_process.py | 17 -------- .../requirements.txt | 0 .../samples.json | 6 --- 8 files changed, 93 deletions(-) delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/aggregate.py delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/data/img2.jpg delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/line_process.py delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/requirements.txt delete mode 100644 examples/flows/evaluation/eval-image-description-accuracy/samples.json diff --git a/examples/flows/evaluation/eval-image-description-accuracy/aggregate.py b/examples/flows/evaluation/eval-image-description-accuracy/aggregate.py deleted file mode 100644 index bf9d10146a0..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/aggregate.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List -from promptflow import tool, log_metric - - -@tool -def calculate_accuracy(grades: List[str]): - accuracy = round((grades.count("Yes") / len(grades)), 2) - log_metric("accuracy", accuracy) - - return accuracy diff --git a/examples/flows/evaluation/eval-image-description-accuracy/data/img2.jpg b/examples/flows/evaluation/eval-image-description-accuracy/data/img2.jpg deleted file mode 100644 index d0fad50cc349ea5cec09a519e9f06b10e3b00ca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5918 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 PX$`xXgrf@S?!Ny&liS2r diff --git a/examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 b/examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 deleted file mode 100644 index 47e41511236..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/evaluate_description_matchness.jinja2 +++ /dev/null @@ -1,10 +0,0 @@ -# system: -As an AI assistant, your task involves interpreting images and responding to questions about the image. -Remember to provide accurate answers based on the information present in the image. - -# user: -Is the answer to the question about the image correct? -Question: {{question}} -Answer: {{answer}} -Image: ![image]({{image_input}}) -Only answer "Yes" or "No", no extra words or punctuation. \ No newline at end of file diff --git a/examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml b/examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml deleted file mode 100644 index 15228104c0a..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/flow.dag.yaml +++ /dev/null @@ -1,40 +0,0 @@ -id: template_eval_flow -name: Template Evaluation Flow -environment: - python_requirements_txt: requirements.txt -inputs: - image: - type: image - default: data/img2.jpg - qustion: - type: string - default: What's in the image? - answer: - type: string - default: A yellow bird -outputs: - results: - type: string - reference: ${evaluate_description_matchness.output} -nodes: -- name: evaluate_description_matchness - type: custom_llm - source: - type: package_with_prompt - tool: promptflow.tools.openai_gpt4v.OpenAI.chat - path: evaluate_description_matchness.jinja2 - inputs: - connection: openai-connection - model: gpt-4-vision-preview - max_tokens: 200 - image_input: ${inputs.image} - question: ${inputs.qustion} - answer: ${inputs.answer} -- name: aggregate - type: python - source: - type: code - path: aggregate.py - inputs: - grades: ${evaluate_description_matchness.output} - aggregation: true diff --git a/examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml b/examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml deleted file mode 100644 index b88024def92..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/flow.meta.yaml +++ /dev/null @@ -1,10 +0,0 @@ -$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json -name: template_eval_flow -display_name: Template Eval Flow -type: evaluate -path: ./flow.dag.yaml -description: Template Evaluation Flow -properties: - promptflow.stage: prod - promptflow.section: template - promptflow.batch_inputs: samples.json diff --git a/examples/flows/evaluation/eval-image-description-accuracy/line_process.py b/examples/flows/evaluation/eval-image-description-accuracy/line_process.py deleted file mode 100644 index 736e66795bf..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/line_process.py +++ /dev/null @@ -1,17 +0,0 @@ -from promptflow import tool - - -@tool -def line_process(groundtruth: str, prediction: str): - """ - This tool processes the prediction of a single line and returns the processed result. - - :param groundtruth: the groundtruth of a single line. - :param prediction: the prediction of a single line. - """ - - processed_result = "" - - # Add your line processing logic here - - return processed_result diff --git a/examples/flows/evaluation/eval-image-description-accuracy/requirements.txt b/examples/flows/evaluation/eval-image-description-accuracy/requirements.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/flows/evaluation/eval-image-description-accuracy/samples.json b/examples/flows/evaluation/eval-image-description-accuracy/samples.json deleted file mode 100644 index e56b5737ea1..00000000000 --- a/examples/flows/evaluation/eval-image-description-accuracy/samples.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "groundtruth": "Tomorrow's weather will be sunny.", - "prediction": "The weather will be sunny tomorrow." - } -] From 43107cc45b98db5cbe08708e1e6bee4d22a22ffd Mon Sep 17 00:00:00 2001 From: minggu Date: Sat, 2 Dec 2023 23:30:13 +0800 Subject: [PATCH 05/35] Remove on-disk image to avoid copyright issue --- .../flows/chat/chat-with-image/flow.dag.yaml | 1 - .../flows/chat/chat-with-image/flow.meta.yaml | 9 --------- .../flows/standard/describe-image/data/img1.jpg | Bin 13290 -> 0 bytes .../flows/standard/describe-image/data/img2.jpg | Bin 5918 -> 0 bytes .../standard/describe-image/data/input.jsonl | 2 -- .../flows/standard/describe-image/flow.dag.yaml | 2 +- 6 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 examples/flows/chat/chat-with-image/flow.meta.yaml delete mode 100644 examples/flows/standard/describe-image/data/img1.jpg delete mode 100644 examples/flows/standard/describe-image/data/img2.jpg delete mode 100644 examples/flows/standard/describe-image/data/input.jsonl diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index 41deff4111b..24ada683c6b 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -1,4 +1,3 @@ -id: template_chat_flow name: Template Chat Flow environment: python_requirements_txt: requirements.txt diff --git a/examples/flows/chat/chat-with-image/flow.meta.yaml b/examples/flows/chat/chat-with-image/flow.meta.yaml deleted file mode 100644 index 9b440bbc9b4..00000000000 --- a/examples/flows/chat/chat-with-image/flow.meta.yaml +++ /dev/null @@ -1,9 +0,0 @@ -$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json -name: template_chat_flow -display_name: Template Chat Flow -type: chat -path: ./flow.dag.yaml -description: Template Chat Flow -properties: - promptflow.stage: prod - promptflow.section: template diff --git a/examples/flows/standard/describe-image/data/img1.jpg b/examples/flows/standard/describe-image/data/img1.jpg deleted file mode 100644 index 4873960fa360ffaa25b6481ba33f34bf0fbcc3df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13290 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 Cdp3#y diff --git a/examples/flows/standard/describe-image/data/img2.jpg b/examples/flows/standard/describe-image/data/img2.jpg deleted file mode 100644 index d0fad50cc349ea5cec09a519e9f06b10e3b00ca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5918 zcmaiYbx_n_)c$98iKX17mvHGux}>`sL`u4qmQG;-5owX`4#9;55orPGE@=q`5s_~A z@%`iX{_+0vK6mb&Idjf==FHr4XP$fR=I_=3xVo~MG5`Vr0O)=JcZ&cDz{iD>lMo|_ zNyrfh5(Ej!{U#FfoLIgkKKpo|lwNUf=Uo z;lzQ!-2y-e0o|7iAqHfCQ@6!688el!fE&oQd&>`S zkbA+y&esevPqI;l~XScP?_-Iv2r+(!ZV9VOc?@P=+{27-U0aRO<||GPCkI> zP-mBHTQ!DXX&;k2vTGarE6;~g&*(NrwX4xx1wQqeg1G-wS!U26&4friP0IO|h4kTd zD4+4Xi{x^m@YU!CnK!ExI&us;UgT=Y|F>fS=-4T%axaO5_L=X<( zCG`_ota&~9SYg_DMX?T37zgAArdbx081~SB)fWD$9*IPnx zzY>mCCseiBoQ#kGigVy!x@A`47H(?F;cVhmGmi6!9wR@YAxqmTIvA()2*6-IWN|oS zbuwo}Q_^RE`QIQY@NB*Lbn$9cZFqMZJ2;q!S7|1Lhl9dzY|K9R)mEQD&Y<{p_Luqa z-nUb%j%VNAR^4RAsEubWX@b7Re!6t<=)MCE^h<7d3`(bIGo~1-?XmV+md8)nnoknZ zeq3o-)m(9qXniRC3GFK+fy(%e7?nm(^;^z>r+>s=q>xgqUmApC6~qEBwzz!T`P`cT{q9p#9HEc)V&7t zVunC*K6GzM6t>_Sn{qgPDOv*EUmqDp-|E4=nO$NI8d7bJDshXTFgJ3FDtaIOnBSy= z1UqY6;!1Uy>E*a!D`=ml>JC^mj~bt#s}42P+g4Gy$t-a&YQXEG}wmBtXG zD@Ug{yc{CGVd$gpDu<7G?ty!$!+j%ZpQcrJyo=W^sX0bHPyWW6tPU7FFS_ArqYW_UJGGvgG)<_{?!#$j(b4%^o)?Ci(B6}FP{BH7 zhV3qvC=OM1_H6ZynFkLuAnt%lJY-&ntz`YNPw=yBg9|Cypu?nq6R_%3wFgY}+&D?@ zRFD7`&(t(NeKQ_yggedz42PUf|3xx79fZW{9Z~xIIdGgD00{Ej>$6@?1Tg8Y)04T_ zZ@RiG?C}L_$Q@qq1mP8x*NXgsRY)ZsWi7Z9D_gW8ufzpV1Yl-yqp^|^G0+Abk zWjI!8OXE+91>V{vGBInn`G#+>gtN#9bXd9v^bub2r=(y4wkUG>yW+VLh3qoS&62(8 zgHjkF2n2gK2?zyg%_teLhIc8vjF`}j3+Ly@i|S>C@(b`V2;gNw-oLhB;8zQm-oY+1 z=Yfjsh{9!Mc}NA7WmHBz@~_-o6DQ1C!a|FjaB^;$!tMHkyVP&d=2_6E*=!%HKT~52 zeKF(ax0+$5*^{%f5Y?Ie|Q$d&X<~$YCDDhJ~`FLWetSXxJe{;9bq#ge`sLfX%pKs1w2!*mb;Pixt+(_7pw``HxP^GWYpk__ZvR#fIUz`-_|x+@`U zL6He1G7RK1yG*pbnI4`Frs=!p(YpyKe*A4_{kJI-s+ERoogv$q$%m$A!&Dy~Vljc+Vg-g(H6S`w9+0)IWa$Cj zgvp%s16!=E2N`R2g*VM?N5?Zped>1vLma&+3j(1(G1 zH_e$N5zZ9smpf-wbk4vC*N5b)mzvpe1QCRU8R6ZaiggB(U&PRecgbW!&^JaPlQ;G# z)yg7rVzMFi!TxZDH@3-Sujx~)6tlv?a1zz5F~IVm69PDgLNlq2RinnPck4Y1@T#-&jl)SK=eyKc}^MCJ2n9ZoY83gUYB{urGnD z1=nJ##oped15GxA3NOQ8j8%Apox=0c3Cx6ribd|1QAug3e6^~l{ox=baLOR|p@Jyu zIqu$6NBP6%%ElH!PVMAfuXEozjW|zvk6Xsi@^<*Vxidc>2HrRXK1b*E!lqj+4@edC z4t5=SJgYby33K3n#*$C#On!RXUf8+OQg6P*`Ao{+zvWvQqGBq=lS{)$Nf(*iEKr}i zr+f$Su_3i&Z>p=$=o3wHQBPiYwJvkP@fhP1t~D?%&)yp6F1Eb?IaW8fqI`BNWFg?K zT!;SIAu}qyD>`zFTm7^&p(7~Q9~~hM+h#FoZ4*1gio7Z(oWG!svuG4IzJISJ9Bt-Ew2)G@{#!fy4u4JpOkjk(2`Iey^-!Xy>85GikN3@e z2hekC^G+G(xwZAAPk+LGC8JT<>Y0PgWKJdRd`dxd?i~&7n_f(cnbDCA?Fg95mrMPL z)0J%bU@8b$wfNmVu($PDw;yH^(uP%RZQ%b2a>Z_Je5GS9FnD#F;KtsvVgAe2JN0si zwWCi&%J=p>K2e;%RPuIUR|=h$V{XdRY_1VCg5Yje??SyZ7#B-R<_Rz%A**@)#r}(x z;yA}5eGMiSOO~ArUeg+D0+%mBQ`w)8)j)D;-lW&}Fal|;CEdV$y#S4Ya`kWViEC8b z$!K@%#s>n*$7_VYxII#vY9`;kPo=(Sm`>4|Yb~}c(cD4b7Dk!o>+$BUzz#p9W|*Rc z@Yc`wmS%=H*p;stSza6<;c>;YiIbFGQ65kUxg`#Z%ejh;j@5~>N`Wu708)uvq6R5; z*3RnJiwF&MnJOleWk-|Sd24>lS8rK&51W$WBp=C4KiNt4B>I};WHb^;@*;$C#oD~; zdDZr!1^4>Qx$+BX*SC~zm(~-Z#f8Y2O!V3ct$=entJY#p8v(!>%_;pe_PV^JL;f?bc%f0%Xn&n|2z$9fUE-W$+`XD&y7V>lM=Vjv~8@D+T?u z;zdu|JAkUV`aD+nLxbZkagE)^Nc^it83h9>*6HSo-AyIY2J*bV)ql%-lCO@Bb3O~n zwzQz-%l;58ov!!B?GCruE$yogx`G>C1}7rd`sUvei6~^WtHDFV)S`&5kTA zF-)-{q$Z0cr|qu*6T@SjiB-c573En<6uE%f5@PQAz5*99lBe&zGREaMA?M|yd;!ji z(rD@|ftTPht8kIU;&Wto;5r-I4P^lQ^*kace)?3;?`6=)*u@>dO-cIw8kTEDV9laX z-4NBn{g!fMU#mIDlRnX2TD0n=9_F!r06X`;fSvyR>$V0-MDt;@x27ET7gsfxCGJW$ z_C28&)D(_|2Vdip(J}ga=b>hW_UQ9%8o={p%`aymgxcM)ujmZDq*hOqY&)Oz>*ER7 zzuwkOrHog_n~fsypN4U}R6w5X`XANo2jc>tSzbRqVqbf>jJIQ3r_)ibr7daI?r6Ba zGY`S&uK7rQ+_{p~fgOm(#~V}?$Z&}6@c@nvl4wXlK>^GyaQwKN?Qt6wb_uBzUG(+C zY`s{o7)3$|yH!sbW7m#YtHO_5W!maEC$ArwR7BAPW--Dl$=_OcU1~No2b#jjr}0nO&DyPow2i(m&9Dw+KJm6hk_)g4n+$NdFh=e zRGv+m{sVnqT6?0FKh=&0xaF4l3z}S8vJ&?94;zZNFZasonPcyKs+)EA88SMIjpN{Q zjJ2%Ut)J>!N#UVhIUlWrEB@a(RmUJo^c-aYQCQ}G>(#K*cCn*)B{KBLv)JC#6k=T2Gkx~O)8U_$msEJEK zWJGzwtW5CPywKW*2z=u6)|%3wqsj778d@zBxXI~+vg^sWUVV{YwQ!G;`m)5ROUuKnjT&-Axl=T(r^jzR;}Ik*JJYv-=aEYx|a7`-;)u(($pj z{akb?QXuM_A%3Db^W=0bzveJ7em*TZxbDS|acm>jipEI0IaZIb-+&;e`)2-E<-ydK zAiCEt3sl!`Nw@Nx9XIxh>uA33e}x2@jo4f)e+m!uMO)_FzqcFtaULmodp#A#rZtIr za+>xMzU%UjQ!Y&mzF64udm-<nkDgd4pvZ$p((4TIJHv$BqD)r5x6R_nT}X>u%)qwbP42y$spP67>7V# z$}PmlbL36dRw;g(e?vDG*h8@#Y3?hGl2@* z;DAJ(jUAqf+JXq^M#Gi2s+06tk-#Z|z=D0fT;RDfvMW-kc zP;F0wV^;e0kfTcDbCvE!B;&9-SCm1sk-SL~a?afFIFD}q+>5c$hmc%_ZBP}G6r`h6 z`LC<&&!hR=&Ig91TWoECnr)Ub*8P&_)Aqr9^X#6QGY}~D3{B3G;Z3f)2{<_krHeOGZzW#-wcD>i|5B?CW0nZ z?!}{7VR5f-x{y7~-k;>D?LZ=(+|x1ag=jV&7!7vF((D>KawW7F#QxjuH@z@B@($ads9vs z|Ec|cPKmt+3MEc^_>?J-uf3@1~Z&^vPXZ3T@sCKHX*6UK5!H z+cP0z3l9;}f>Vsgm&Ef|>R!%I`et=i3Mu(+>1KaT*>dx5itU#Vao50Xq@;cay2B2n zq|5)oGiB@(lk!f2YmO}kM%xKjBTpU+%`e%`Yls;=Rbq-TTFNWVEX+sn^nlD_$=IKq zK15lNr)!Z@3x14lx}842ksx9^o4ZAIRE&|9R12*nR<1y1 z-$W%ShnB~tPI2abdlWxdCm(RvmQX{!4HDA}Xh1xbE zi|zpOo73TXrl_Q;k|&%3%b6=oua;GYTx(!^?dZR{)!6+R0vhKbArl)7~!ab*Ya>M90jDcG61DT2zgyiLI!~F9f}2eK%4~rj)FTwULK7~ z9W$2K&*NIx64-9o7%0Q=+EqyFhQzp+tL+?T%?`y=ReM^f(&pDNJicYpD2`cgVp87p PX$`xXgrf@S?!Ny&liS2r diff --git a/examples/flows/standard/describe-image/data/input.jsonl b/examples/flows/standard/describe-image/data/input.jsonl deleted file mode 100644 index 917261af56f..00000000000 --- a/examples/flows/standard/describe-image/data/input.jsonl +++ /dev/null @@ -1,2 +0,0 @@ -{"question": "Please describe this image:", "input_image": {"data:image/jpg;path": "img1.jpg"}} -{"question": "Please describe images:", "input_image": {"data:image/jpg;path": "img2.jpg"}} \ No newline at end of file diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 3b88a7b06d3..0fe2b2380bb 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -4,7 +4,7 @@ inputs: default: Please describe this image. input_image: type: image - default: data/img1.jpg + default: https://developer.microsoft.com/_devcom/images/logo-ms-social.png outputs: answer: type: string From 02d670c12f8f28f99133eb01d4291a866ce5d9d4 Mon Sep 17 00:00:00 2001 From: minggu Date: Sat, 2 Dec 2023 23:46:08 +0800 Subject: [PATCH 06/35] Add default input --- examples/flows/chat/chat-with-image/flow.dag.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index 24ada683c6b..fd5658ebf0e 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -7,6 +7,9 @@ inputs: is_chat_history: true question: type: list + default: + - How many colors can you see? + - {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"} is_chat_input: true outputs: answer: From 709b712f70d6a84dc4790453017786df3159e9f0 Mon Sep 17 00:00:00 2001 From: minggu Date: Sat, 2 Dec 2023 23:57:38 +0800 Subject: [PATCH 07/35] Add image type to flow input --- docs/reference/flow-yaml-schema-reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/flow-yaml-schema-reference.md b/docs/reference/flow-yaml-schema-reference.md index f0a64fb61f6..35991c3c5f6 100644 --- a/docs/reference/flow-yaml-schema-reference.md +++ b/docs/reference/flow-yaml-schema-reference.md @@ -25,9 +25,9 @@ The source JSON schema can be found at [Flow.schema.json](https://azuremlschemas | Key | Type | Description | Allowed values | |-------------------|-------------------------------------------|------------------------------------------------------|-----------------------------------------------------| -| `type` | string | The type of flow input. | `int`, `double`, `bool`, `string`, `list`, `object` | +| `type` | string | The type of flow input. | `int`, `double`, `bool`, `string`, `list`, `object`, `image` | | `description` | string | Description of the input. | | -| `default` | int, double, bool, string, list or object | The default value for the input. | | +| `default` | int, double, bool, string, list, object, image | The default value for the input. | | | `is_chat_input` | boolean | Whether the input is the chat flow input. | | | `is_chat_history` | boolean | Whether the input is the chat history for chat flow. | | From 11fdc7ddb3723716381eb42955a210046c9254db Mon Sep 17 00:00:00 2001 From: minggu Date: Sun, 3 Dec 2023 09:54:49 +0800 Subject: [PATCH 08/35] Add workflow for chat_with_image --- .../samples_flows_chat_chat_with_image.yml | 96 +++++++++++++++++++ examples/README.md | 1 + examples/flows/chat/chat-with-image/README.md | 52 ++++++++++ 3 files changed, 149 insertions(+) create mode 100644 .github/workflows/samples_flows_chat_chat_with_image.yml create mode 100644 examples/flows/chat/chat-with-image/README.md diff --git a/.github/workflows/samples_flows_chat_chat_with_image.yml b/.github/workflows/samples_flows_chat_chat_with_image.yml new file mode 100644 index 00000000000..092bb753590 --- /dev/null +++ b/.github/workflows/samples_flows_chat_chat_with_image.yml @@ -0,0 +1,96 @@ +# This code is autogenerated. +# Code is generated by running custom script: python3 readme.py +# Any manual changes to this file may cause incorrect behavior. +# Any manual changes will be overwritten if the code is regenerated. + +name: samples_flows_chat_chat_with_image +on: + schedule: + - cron: "16 19 * * *" # Every day starting at 3:16 BJT + pull_request: + branches: [ main ] + paths: [ examples/flows/chat/chat-with-image/**, examples/*requirements.txt, .github/workflows/samples_flows_chat_chat_with_image.yml ] + workflow_dispatch: + +env: + IS_IN_CI_PIPELINE: "true" + +jobs: + samples_readme_ci: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Python 3.9 environment + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Generate config.json for canary workspace (scheduled runs only) + if: github.event_name == 'schedule' + run: echo '${{ secrets.TEST_WORKSPACE_CONFIG_JSON_CANARY }}' > ${{ github.workspace }}/examples/config.json + - name: Generate config.json for production workspace + if: github.event_name != 'schedule' + run: echo '${{ secrets.EXAMPLE_WORKSPACE_CONFIG_JSON_PROD }}' > ${{ github.workspace }}/examples/config.json + - name: Prepare requirements + working-directory: examples + run: | + if [[ -e requirements.txt ]]; then + python -m pip install --upgrade pip + pip install -r requirements.txt + fi + - name: Prepare dev requirements + working-directory: examples + run: | + python -m pip install --upgrade pip + pip install -r dev_requirements.txt + - name: Refine .env file + working-directory: examples/flows/chat/chat-with-image + run: | + AOAI_API_KEY=${{ secrets.AOAI_API_KEY_TEST }} + AOAI_API_ENDPOINT=${{ secrets.AOAI_API_ENDPOINT_TEST }} + AOAI_API_ENDPOINT=$(echo ${AOAI_API_ENDPOINT//\//\\/}) + if [[ -e .env.example ]]; then + echo "env replacement" + sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example + mv .env.example .env + fi + - name: Create run.yml + working-directory: examples/flows/chat/chat-with-image + run: | + gpt_base=${{ secrets.AOAI_API_ENDPOINT_TEST }} + gpt_base=$(echo ${gpt_base//\//\\/}) + if [[ -e run.yml ]]; then + sed -i -e "s/\${azure_open_ai_connection.api_key}/${{ secrets.AOAI_API_KEY_TEST }}/g" -e "s/\${azure_open_ai_connection.api_base}/$gpt_base/g" run.yml + fi + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Extract Steps examples/flows/chat/chat-with-image/README.md + working-directory: ${{ github.workspace }} + run: | + python scripts/readme/extract_steps_from_readme.py -f examples/flows/chat/chat-with-image/README.md -o examples/flows/chat/chat-with-image + - name: Cat script + working-directory: examples/flows/chat/chat-with-image + run: | + cat bash_script.sh + - name: Run scripts + working-directory: examples/flows/chat/chat-with-image + run: | + export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} + export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} + export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} + export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_CANARY }} + bash bash_script.sh + - name: Pip List for Debug + if : ${{ always() }} + working-directory: examples/flows/chat/chat-with-image + run: | + pip list + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: artifact + path: examples/flows/chat/chat-with-image/bash_script.sh \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 6780acbc9c2..11634671b8c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -74,6 +74,7 @@ ------|--------|------------- | [basic-chat](flows/chat/basic-chat/README.md) | [![samples_flows_chat_basic_chat](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_basic_chat.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_basic_chat.yml) | This example shows how to create a basic chat flow | | [chat-math-variant](flows/chat/chat-math-variant/README.md) | [![samples_flows_chat_chat_math_variant](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_math_variant.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_math_variant.yml) | This is a prompt tuning case with 3 prompt variants for math question answering | +| [chat-with-image](flows/chat/chat-with-image/README.md) | [![samples_flows_chat_chat_with_image](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_image.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_image.yml) | This flow demonstrates how to create a chatbot that can take image and text as input | | [chat-with-pdf](flows/chat/chat-with-pdf/README.md) | [![samples_flows_chat_chat_with_pdf](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_pdf.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_pdf.yml) | This is a simple flow that allow you to ask questions about the content of a PDF file and get answers | | [chat-with-wikipedia](flows/chat/chat-with-wikipedia/README.md) | [![samples_flows_chat_chat_with_wikipedia](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_wikipedia.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_chat_chat_with_wikipedia.yml) | This flow demonstrates how to create a chatbot that can remember previous interactions and use the conversation history to generate next message | diff --git a/examples/flows/chat/chat-with-image/README.md b/examples/flows/chat/chat-with-image/README.md new file mode 100644 index 00000000000..0dad7f75993 --- /dev/null +++ b/examples/flows/chat/chat-with-image/README.md @@ -0,0 +1,52 @@ +# Chat With Image + +This flow demonstrates how to create a chatbot that can take image and text as input. + +Tools used in this flow: +- `OpenAI GPT-4V` tool + +## Prerequisites + +Install promptflow sdk and other dependencies in this folder: +```bash +pip install -r requirements.txt +``` + +## What you will learn + +In this flow, you will learn +- how to compose a chat flow with image and text as input. The chat input should be a list of text and/or images. + +## Getting started + +### 1 Create connection for OpenAI GPT-4V tool to use +Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an "OpenAI" connection. If you do not have an OpenAI account, please refer to [OpenAI](https://platform.openai.com/) for more details. + +```bash +# Override keys with --set to avoid yaml file changes +pf connection create --file ../../../connections/openai.yml --set api_key= +``` + +Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `openai_connection`. +```bash +# show registered connection +pf connection show --name openai_connection +``` + +### 2 Start chatting + +```bash +# run chat flow with default question in flow.dag.yaml +pf flow test --flow . + +# run chat flow with new question +pf flow test --flow . --inputs question="[\"How many colors can you see?\", {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}]" + +# start a interactive chat session in CLI +pf flow test --flow . --interactive + +# start a interactive chat session in CLI with verbose info +pf flow test --flow . --interactive --verbose +``` + + From 2056946c08053947c03f61c41d5265cca87b9f1b Mon Sep 17 00:00:00 2001 From: minggu Date: Sun, 3 Dec 2023 09:57:01 +0800 Subject: [PATCH 09/35] Remove image_pass_through flow --- .../standard/image-pass-through/flow.dag.yaml | 29 ------------------ .../standard/image-pass-through/logo.jpg | Bin 140150 -> 0 bytes .../standard/image-pass-through/logo_2.png | Bin 39417 -> 0 bytes .../image-pass-through/pick_an_image.py | 9 ------ 4 files changed, 38 deletions(-) delete mode 100644 examples/flows/standard/image-pass-through/flow.dag.yaml delete mode 100644 examples/flows/standard/image-pass-through/logo.jpg delete mode 100644 examples/flows/standard/image-pass-through/logo_2.png delete mode 100644 examples/flows/standard/image-pass-through/pick_an_image.py diff --git a/examples/flows/standard/image-pass-through/flow.dag.yaml b/examples/flows/standard/image-pass-through/flow.dag.yaml deleted file mode 100644 index af3eccc8075..00000000000 --- a/examples/flows/standard/image-pass-through/flow.dag.yaml +++ /dev/null @@ -1,29 +0,0 @@ -inputs: - image: - type: image - default: https://img.mp.itc.cn/upload/20160526/0c2848cb6e614b4f9345940fcba2edc7_th.jpg - is_chat_input: false -outputs: - output: - type: image - reference: ${python_node_2.output} -nodes: -- name: python_node - type: python - source: - type: code - path: pick_an_image.py - inputs: - image_1: ${inputs.image} - image_2: logo_2.png - use_variants: false -- name: python_node_2 - type: python - source: - type: code - path: pick_an_image.py - inputs: - image_1: ${python_node.output} - image_2: logo.jpg - use_variants: false -node_variants: {} diff --git a/examples/flows/standard/image-pass-through/logo.jpg b/examples/flows/standard/image-pass-through/logo.jpg deleted file mode 100644 index 155609310c8035a8fd06efa61d2cecb5d3f5eb15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140150 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

Ghkzv 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

9*Yk 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 fpJk&e9(IC}qIab*^{ZRf+vx(g{VaE%?S7Iu) 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 YOYA{2cI`Ia3eN3`pq0$V!)GP_8&Kr}NdN!< diff --git a/examples/flows/standard/image-pass-through/pick_an_image.py b/examples/flows/standard/image-pass-through/pick_an_image.py deleted file mode 100644 index 1c358e83b4a..00000000000 --- a/examples/flows/standard/image-pass-through/pick_an_image.py +++ /dev/null @@ -1,9 +0,0 @@ -import random - -from promptflow.contracts.multimedia import Image -from promptflow import tool - - -@tool -def pick_an_image(image_1: Image, image_2: Image) -> Image: - return image_1 From b86b49ca7916a1de4041713883e35aaaa8f5dd65 Mon Sep 17 00:00:00 2001 From: minggu Date: Wed, 6 Dec 2023 13:52:25 +0800 Subject: [PATCH 10/35] Add doc for describe image sample flow --- .../flows/standard/describe-image/README.md | 58 +++++++++++++++++++ .../flows/standard/describe-image/data.jsonl | 2 + 2 files changed, 60 insertions(+) create mode 100644 examples/flows/standard/describe-image/README.md create mode 100644 examples/flows/standard/describe-image/data.jsonl diff --git a/examples/flows/standard/describe-image/README.md b/examples/flows/standard/describe-image/README.md new file mode 100644 index 00000000000..6851920e6b4 --- /dev/null +++ b/examples/flows/standard/describe-image/README.md @@ -0,0 +1,58 @@ +# Describe image flow +A flow that take image input and uses OpenAI GPT-4V tool to describe it. We also added a pass_through node from input to output to demo PromptFlow's ability to output image in both node output and flow output. + +Tools used in this flow: +- `OpenAI GPT-4V` tool +- custom `python` Tool + +Connections used in this flow: +- OpenAI Connection + +## Prerequisites + +Install promptflow sdk and other dependencies: +```bash +pip install -r requirements.txt +``` + +## Run flow + +- Prepare OpenAI connection +Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an "OpenAI" connection. If you do not have an OpenAI account, please refer to [OpenAI](https://platform.openai.com/) for more details. + +- Test flow/node +```bash +# test with default input value in flow.dag.yaml +pf flow test --flow . + +# test with flow inputs +pf flow test --flow . --inputs question="How many colors can you see?" input_image="{\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}" + +``` + +- Create run with multiple lines data +```bash +# using environment from .env file (loaded in user code: hello.py) +pf run create --flow . --data ./data.jsonl --column-mapping question='${data.question}' --stream +``` + +You can also skip providing `column-mapping` if provided data has same column name as the flow. +Reference [here](https://aka.ms/pf/column-mapping) for default behavior when `column-mapping` not provided in CLI. + +- List and show run meta +```bash +# list created run +pf run list + +# get a sample run name +name=$(pf run list -r 10 | jq '.[] | select(.name | contains("basic_variant_0")) | .name'| head -n 1 | tr -d '"') + +# show specific run detail +pf run show --name $name + +# show output +pf run show-details --name $name + +# visualize run in browser +pf run visualize --name $name +``` diff --git a/examples/flows/standard/describe-image/data.jsonl b/examples/flows/standard/describe-image/data.jsonl new file mode 100644 index 00000000000..a52f6b67c01 --- /dev/null +++ b/examples/flows/standard/describe-image/data.jsonl @@ -0,0 +1,2 @@ +{"question": "How many colors are there in the image?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}} +{"question": "What's this image about?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/404.png"}} \ No newline at end of file From 8708ddc882de75c4060c0c6a6c142ed02a758b8f Mon Sep 17 00:00:00 2001 From: minggu Date: Wed, 6 Dec 2023 13:52:44 +0800 Subject: [PATCH 11/35] Add doc for image --- docs/how-to-guides/use-image-in-flow.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/how-to-guides/use-image-in-flow.md diff --git a/docs/how-to-guides/use-image-in-flow.md b/docs/how-to-guides/use-image-in-flow.md new file mode 100644 index 00000000000..38dfe23ace6 --- /dev/null +++ b/docs/how-to-guides/use-image-in-flow.md @@ -0,0 +1,15 @@ +PromptFlow support image input/output by defining a contract of image data. + +# Data class +promptflow.contracts.multimedia.Image +Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin of the image, which would be useful if you want to pass the url instead of content to APIs like LLM. + +# Serialization/Deserialization +Url +Base64 +File Reference + +# Batch Input data +Batch input data containing image can be of 2 formats: +1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. +2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. \ No newline at end of file From 3919a07cc9139918f30b6af2588e7edf2f2312d7 Mon Sep 17 00:00:00 2001 From: minggu Date: Thu, 7 Dec 2023 08:09:53 +0800 Subject: [PATCH 12/35] enrich guide --- docs/how-to-guides/use-image-in-flow.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/how-to-guides/use-image-in-flow.md b/docs/how-to-guides/use-image-in-flow.md index 38dfe23ace6..8c7158f6659 100644 --- a/docs/how-to-guides/use-image-in-flow.md +++ b/docs/how-to-guides/use-image-in-flow.md @@ -1,15 +1,28 @@ -PromptFlow support image input/output by defining a contract of image data. +PromptFlow defines a contract to represent image data. # Data class -promptflow.contracts.multimedia.Image +`promptflow.contracts.multimedia.Image` Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin of the image, which would be useful if you want to pass the url instead of content to APIs like LLM. # Serialization/Deserialization -Url -Base64 -File Reference +Promptflow uses a special dict to preprent image. +`{"data:image/;": ""}` +`` can be html standard image types which can help previewing correctly, or it can be `*` for unknown type. +`` is the image serilized representation, there are 3 supported types: + +## url +It can point to a public accessable web url. E.g. +{"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"} + +## base64 +It can be the base64 encoding of the image. E.g. +{"data:image/png;base64": ""} + +## path +It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative path to the containing folder of that file is recommended, as in the case of flow IO data. E.g. +{"data:image/png;path": "./my-image.png"} # Batch Input data Batch input data containing image can be of 2 formats: 1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. -2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. \ No newline at end of file +2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. From 10a4d7b2eb5af624e872f33f60a8f4fd8d269dc2 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Thu, 7 Dec 2023 11:42:36 +0800 Subject: [PATCH 13/35] Rename to "process-image-in-flow" --- docs/how-to-guides/process-image-in-flow.md | 52 +++++++++++++++++++++ docs/how-to-guides/use-image-in-flow.md | 28 ----------- 2 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 docs/how-to-guides/process-image-in-flow.md delete mode 100644 docs/how-to-guides/use-image-in-flow.md diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md new file mode 100644 index 00000000000..a8bb0b5a6d2 --- /dev/null +++ b/docs/how-to-guides/process-image-in-flow.md @@ -0,0 +1,52 @@ +# Process image in flow +PromptFlow defines a contract to represent image data. + +## Data class +`promptflow.contracts.multimedia.Image` +Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin of the image, which would be useful if you want to pass the url instead of content to APIs like LLM. + +## Data type in flow input +Set the type of flow input to `image` and promptflow will treat it as an image. + +## Reference image in prompt template +In prompt templates that support image (e.g. in OpenAI-GPT-4V tool), using markdown syntax to denote that a template input is an image: `![image]({{test_image}})`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model. + +## Serialization/Deserialization +Promptflow uses a special dict to preprent image. +`{"data:image/;": ""}` + +- `` can be html standard [mime](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type. +- `` is the image serilized representation, there are 3 supported types: + + - url + + It can point to a public accessable web url. E.g. + + {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"} + - base64 + + It can be the base64 encoding of the image. E.g. + + {"data:image/png;base64": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII="} + + - path + + It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative path to the containing folder of that file is recommended, as in the case of flow IO data. E.g. + + {"data:image/png;path": "./my-image.png"} + +## Batch Input data +Batch input data containing image can be of 2 formats: +1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. +2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. Here is a sample batch input: + ``` + BatchInputFolder + |----input.jsonl + |----image1.png + |----image2.png + ``` + Content of `input.jsonl` + ```jsonl + {"question": "How many colors are there in the image?", "input_image": {"data:image/png;path": "image1.png"}} + {"question": "What's this image about?", "input_image": {"data:image/png;path": "image2.png"}} + ``` diff --git a/docs/how-to-guides/use-image-in-flow.md b/docs/how-to-guides/use-image-in-flow.md deleted file mode 100644 index 8c7158f6659..00000000000 --- a/docs/how-to-guides/use-image-in-flow.md +++ /dev/null @@ -1,28 +0,0 @@ -PromptFlow defines a contract to represent image data. - -# Data class -`promptflow.contracts.multimedia.Image` -Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin of the image, which would be useful if you want to pass the url instead of content to APIs like LLM. - -# Serialization/Deserialization -Promptflow uses a special dict to preprent image. -`{"data:image/;": ""}` -`` can be html standard image types which can help previewing correctly, or it can be `*` for unknown type. -`` is the image serilized representation, there are 3 supported types: - -## url -It can point to a public accessable web url. E.g. -{"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"} - -## base64 -It can be the base64 encoding of the image. E.g. -{"data:image/png;base64": ""} - -## path -It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative path to the containing folder of that file is recommended, as in the case of flow IO data. E.g. -{"data:image/png;path": "./my-image.png"} - -# Batch Input data -Batch input data containing image can be of 2 formats: -1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. -2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. From f1e198f8c41c1f4b8cc3cd6e0546ed97c902b38a Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Thu, 7 Dec 2023 19:35:38 +0800 Subject: [PATCH 14/35] Update flow readme --- examples/flows/chat/chat-with-image/README.md | 2 +- examples/flows/standard/describe-image/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flows/chat/chat-with-image/README.md b/examples/flows/chat/chat-with-image/README.md index 0dad7f75993..55658de64bf 100644 --- a/examples/flows/chat/chat-with-image/README.md +++ b/examples/flows/chat/chat-with-image/README.md @@ -40,7 +40,7 @@ pf connection show --name openai_connection pf flow test --flow . # run chat flow with new question -pf flow test --flow . --inputs question="[\"How many colors can you see?\", {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}]" +pf flow test --flow . --inputs question='["How many colors can you see?", {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}]' # start a interactive chat session in CLI pf flow test --flow . --interactive diff --git a/examples/flows/standard/describe-image/README.md b/examples/flows/standard/describe-image/README.md index 6851920e6b4..381038f58e2 100644 --- a/examples/flows/standard/describe-image/README.md +++ b/examples/flows/standard/describe-image/README.md @@ -26,7 +26,7 @@ Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an " pf flow test --flow . # test with flow inputs -pf flow test --flow . --inputs question="How many colors can you see?" input_image="{\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}" +pf flow test --flow . --inputs question="How many colors can you see?" input_image="https://developer.microsoft.com/_devcom/images/logo-ms-social.png" ``` From d803c212dcd586c70c4e7403f27c462bf47829ad Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Thu, 7 Dec 2023 19:53:18 +0800 Subject: [PATCH 15/35] Polish the doc --- docs/how-to-guides/process-image-in-flow.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md index a8bb0b5a6d2..b4693ec509f 100644 --- a/docs/how-to-guides/process-image-in-flow.md +++ b/docs/how-to-guides/process-image-in-flow.md @@ -3,7 +3,7 @@ PromptFlow defines a contract to represent image data. ## Data class `promptflow.contracts.multimedia.Image` -Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin of the image, which would be useful if you want to pass the url instead of content to APIs like LLM. +Image class is a subclass of `bytes`, thus you can access the binary data by directly using the object. It has an extra attribute `source_url` to store the origin url of the image, which would be useful if you want to pass the url instead of content of image to APIs like GPT-4V model. ## Data type in flow input Set the type of flow input to `image` and promptflow will treat it as an image. @@ -31,13 +31,17 @@ Promptflow uses a special dict to preprent image. - path - It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative path to the containing folder of that file is recommended, as in the case of flow IO data. E.g. + It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative to the containing folder of that file is recommended, as in the case of flow IO data. E.g. {"data:image/png;path": "./my-image.png"} ## Batch Input data Batch input data containing image can be of 2 formats: -1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. +1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. E.g. + ```jsonl + {"question": "How many colors are there in the image?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}} + {"question": "What's this image about?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/404.png"}} + ``` 2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. Here is a sample batch input: ``` BatchInputFolder From 6482967d3ea4fc5faf7bffa764dd2646fad99e92 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Thu, 7 Dec 2023 20:01:27 +0800 Subject: [PATCH 16/35] Add workflow for describe-image flow --- .../samples_flows_standard_describe_image.yml | 96 +++++++++++++++++++ examples/README.md | 1 + 2 files changed, 97 insertions(+) create mode 100644 .github/workflows/samples_flows_standard_describe_image.yml diff --git a/.github/workflows/samples_flows_standard_describe_image.yml b/.github/workflows/samples_flows_standard_describe_image.yml new file mode 100644 index 00000000000..77859cced7a --- /dev/null +++ b/.github/workflows/samples_flows_standard_describe_image.yml @@ -0,0 +1,96 @@ +# This code is autogenerated. +# Code is generated by running custom script: python3 readme.py +# Any manual changes to this file may cause incorrect behavior. +# Any manual changes will be overwritten if the code is regenerated. + +name: samples_flows_standard_describe_image +on: + schedule: + - cron: "9 19 * * *" # Every day starting at 3:9 BJT + pull_request: + branches: [ main ] + paths: [ examples/flows/standard/describe-image/**, examples/*requirements.txt, .github/workflows/samples_flows_standard_describe_image.yml ] + workflow_dispatch: + +env: + IS_IN_CI_PIPELINE: "true" + +jobs: + samples_readme_ci: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Python 3.9 environment + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Generate config.json for canary workspace (scheduled runs only) + if: github.event_name == 'schedule' + run: echo '${{ secrets.TEST_WORKSPACE_CONFIG_JSON_CANARY }}' > ${{ github.workspace }}/examples/config.json + - name: Generate config.json for production workspace + if: github.event_name != 'schedule' + run: echo '${{ secrets.EXAMPLE_WORKSPACE_CONFIG_JSON_PROD }}' > ${{ github.workspace }}/examples/config.json + - name: Prepare requirements + working-directory: examples + run: | + if [[ -e requirements.txt ]]; then + python -m pip install --upgrade pip + pip install -r requirements.txt + fi + - name: Prepare dev requirements + working-directory: examples + run: | + python -m pip install --upgrade pip + pip install -r dev_requirements.txt + - name: Refine .env file + working-directory: examples/flows/standard/describe-image + run: | + AOAI_API_KEY=${{ secrets.AOAI_API_KEY_TEST }} + AOAI_API_ENDPOINT=${{ secrets.AOAI_API_ENDPOINT_TEST }} + AOAI_API_ENDPOINT=$(echo ${AOAI_API_ENDPOINT//\//\\/}) + if [[ -e .env.example ]]; then + echo "env replacement" + sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example + mv .env.example .env + fi + - name: Create run.yml + working-directory: examples/flows/standard/describe-image + run: | + gpt_base=${{ secrets.AOAI_API_ENDPOINT_TEST }} + gpt_base=$(echo ${gpt_base//\//\\/}) + if [[ -e run.yml ]]; then + sed -i -e "s/\${azure_open_ai_connection.api_key}/${{ secrets.AOAI_API_KEY_TEST }}/g" -e "s/\${azure_open_ai_connection.api_base}/$gpt_base/g" run.yml + fi + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Extract Steps examples/flows/standard/describe-image/README.md + working-directory: ${{ github.workspace }} + run: | + python scripts/readme/extract_steps_from_readme.py -f examples/flows/standard/describe-image/README.md -o examples/flows/standard/describe-image + - name: Cat script + working-directory: examples/flows/standard/describe-image + run: | + cat bash_script.sh + - name: Run scripts + working-directory: examples/flows/standard/describe-image + run: | + export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} + export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} + export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} + export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_CANARY }} + bash bash_script.sh + - name: Pip List for Debug + if : ${{ always() }} + working-directory: examples/flows/standard/describe-image + run: | + pip list + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: artifact + path: examples/flows/standard/describe-image/bash_script.sh \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 11634671b8c..3ef8d3682a7 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,6 +48,7 @@ | [conditional-flow-for-if-else](flows/standard/conditional-flow-for-if-else/README.md) | [![samples_flows_standard_conditional_flow_for_if_else](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_if_else.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_if_else.yml) | This example is a conditional flow for if-else scenario | | [conditional-flow-for-switch](flows/standard/conditional-flow-for-switch/README.md) | [![samples_flows_standard_conditional_flow_for_switch](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_switch.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_switch.yml) | This example is a conditional flow for switch scenario | | [customer-intent-extraction](flows/standard/customer-intent-extraction/README.md) | [![samples_flows_standard_customer_intent_extraction](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_customer_intent_extraction.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_customer_intent_extraction.yml) | This sample is using OpenAI chat model(ChatGPT/GPT4) to identify customer intent from customer's question | +| [describe-image](flows/standard/describe-image/README.md) | [![samples_flows_standard_describe_image](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml) | A flow that take image input and uses OpenAI GPT-4V tool to describe it | | [flow-with-additional-includes](flows/standard/flow-with-additional-includes/README.md) | [![samples_flows_standard_flow_with_additional_includes](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_additional_includes.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_additional_includes.yml) | User sometimes need to reference some common files or folders, this sample demos how to solve the problem using additional_includes | | [flow-with-symlinks](flows/standard/flow-with-symlinks/README.md) | [![samples_flows_standard_flow_with_symlinks](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_symlinks.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_symlinks.yml) | User sometimes need to reference some common files or folders, this sample demos how to solve the problem using symlinks | | [gen-docstring](flows/standard/gen-docstring/README.md) | [![samples_flows_standard_gen_docstring](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_gen_docstring.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_gen_docstring.yml) | This example can help you automatically generate Python code's docstring and return the modified code | From 3347d93562c9f0b27deff7294fa2bd7f77e7939b Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Fri, 8 Dec 2023 14:15:01 +0800 Subject: [PATCH 17/35] Fix some comments --- docs/how-to-guides/process-image-in-flow.md | 8 +++++--- examples/flows/chat/chat-with-image/flow.dag.yaml | 1 - .../standard/describe-image/question_on_image.jinja2 | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md index b4693ec509f..79f5b45ef0a 100644 --- a/docs/how-to-guides/process-image-in-flow.md +++ b/docs/how-to-guides/process-image-in-flow.md @@ -9,10 +9,10 @@ Image class is a subclass of `bytes`, thus you can access the binary data by dir Set the type of flow input to `image` and promptflow will treat it as an image. ## Reference image in prompt template -In prompt templates that support image (e.g. in OpenAI-GPT-4V tool), using markdown syntax to denote that a template input is an image: `![image]({{test_image}})`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model. +In prompt templates that support image (e.g. in OpenAI GPT-4V tool), using markdown syntax to denote that a template input is an image: `![image]({{test_image}})`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model. ## Serialization/Deserialization -Promptflow uses a special dict to preprent image. +Promptflow uses a special dict to representnt image. `{"data:image/;": ""}` - `` can be html standard [mime](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type. @@ -35,6 +35,8 @@ Promptflow uses a special dict to preprent image. {"data:image/png;path": "./my-image.png"} +Please note that `path` representation is not supported in Deployment scenario. + ## Batch Input data Batch input data containing image can be of 2 formats: 1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. E.g. @@ -42,7 +44,7 @@ Batch input data containing image can be of 2 formats: {"question": "How many colors are there in the image?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}} {"question": "What's this image about?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/404.png"}} ``` -2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The reference file are stored in the folder and there relative path to the root path is used as path in the file reference. Here is a sample batch input: +2. A folder containing a jsonl file under root path, which contains serialized image in File Reference format. The referenced file are stored in the folder and their relative path to the root path is used as path in the file reference. Here is a sample batch input, note that the name of `input.jsonl` is arbitrary as long as it's a jsonl file: ``` BatchInputFolder |----input.jsonl diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index fd5658ebf0e..ecb8d71f0c4 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -1,4 +1,3 @@ -name: Template Chat Flow environment: python_requirements_txt: requirements.txt inputs: diff --git a/examples/flows/standard/describe-image/question_on_image.jinja2 b/examples/flows/standard/describe-image/question_on_image.jinja2 index efabb9c712b..23cd39faafd 100644 --- a/examples/flows/standard/describe-image/question_on_image.jinja2 +++ b/examples/flows/standard/describe-image/question_on_image.jinja2 @@ -1,5 +1,6 @@ # system: -You are a helpful assistant. +As an AI assistant, your task involves interpreting images and responding to questions about the image. +Remember to provide accurate answers based on the information present in the image. # user: {{question}} From e321013c0a44817a38b1482e31410f6afbd251cc Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 20:27:38 +0800 Subject: [PATCH 18/35] fix typo --- docs/how-to-guides/process-image-in-flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md index 79f5b45ef0a..d6f71513ddf 100644 --- a/docs/how-to-guides/process-image-in-flow.md +++ b/docs/how-to-guides/process-image-in-flow.md @@ -12,7 +12,7 @@ Set the type of flow input to `image` and promptflow will treat it as an image. In prompt templates that support image (e.g. in OpenAI GPT-4V tool), using markdown syntax to denote that a template input is an image: `![image]({{test_image}})`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model. ## Serialization/Deserialization -Promptflow uses a special dict to representnt image. +Promptflow uses a special dict to represent image. `{"data:image/;": ""}` - `` can be html standard [mime](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type. From a1b0e55f944e86406583594522e3b5516b8f6489 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 20:29:46 +0800 Subject: [PATCH 19/35] Add process-image-in-flow to index --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 22be0ca7208..ec3a46fe756 100644 --- a/docs/index.md +++ b/docs/index.md @@ -45,6 +45,7 @@ This documentation site contains guides for prompt flow [sdk, cli](https://pypi. - [Tune prompts using variants](how-to-guides/tune-prompts-with-variants.md)
- [Develop custom tool](how-to-guides/develop-a-tool/create-and-use-tool-package.md)
- [Deploy a flow](how-to-guides/deploy-a-flow/index.md)
+ - [Process image in flow](how-to-guides/process-image-in-flow.md) " ``` From de7c8922218e0a587bf73bc5ee71d974ded12b21 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 21:01:26 +0800 Subject: [PATCH 20/35] Fix typo --- docs/how-to-guides/process-image-in-flow.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md index d6f71513ddf..21523ae3878 100644 --- a/docs/how-to-guides/process-image-in-flow.md +++ b/docs/how-to-guides/process-image-in-flow.md @@ -16,7 +16,7 @@ Promptflow uses a special dict to represent image. `{"data:image/;": ""}` - `` can be html standard [mime](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type. -- `` is the image serilized representation, there are 3 supported types: +- `` is the image serialized representation, there are 3 supported types: - url @@ -31,7 +31,7 @@ Promptflow uses a special dict to represent image. - path - It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serlized image representation is stored in a file, relative to the containing folder of that file is recommended, as in the case of flow IO data. E.g. + It can reference an image file on local disk. Both absolute path and relative path are supported, but in the cases where the serialized image representation is stored in a file, relative to the containing folder of that file is recommended, as in the case of flow IO data. E.g. {"data:image/png;path": "./my-image.png"} From b06092213872f1ff65c13c566edac489df305448 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 21:06:45 +0800 Subject: [PATCH 21/35] Update connection to openai_connection --- examples/flows/chat/chat-with-image/flow.dag.yaml | 2 +- examples/flows/standard/describe-image/flow.dag.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index ecb8d71f0c4..8c8a26e80b2 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -23,7 +23,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: chat.jinja2 inputs: - connection: openai-connection + connection: openai_connection model: gpt-4-vision-preview max_tokens: 200 chat_history: ${inputs.chat_history} diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 0fe2b2380bb..92ca1bf0bf9 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -20,7 +20,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: question_on_image.jinja2 inputs: - connection: openai-connection + connection: openai_connection question: ${inputs.question} test_image: ${passthrough.output} model: gpt-4-vision-preview From 36deae74c06b633aebd73980ab17bf471aa4e167 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 21:35:34 +0800 Subject: [PATCH 22/35] Flip image horizontal instead of pass through --- examples/flows/standard/describe-image/README.md | 2 +- .../flows/standard/describe-image/flip_image.py | 14 ++++++++++++++ .../flows/standard/describe-image/flow.dag.yaml | 8 ++++---- .../flows/standard/describe-image/passthrough.py | 7 ------- 4 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 examples/flows/standard/describe-image/flip_image.py delete mode 100644 examples/flows/standard/describe-image/passthrough.py diff --git a/examples/flows/standard/describe-image/README.md b/examples/flows/standard/describe-image/README.md index 381038f58e2..7c3f95733f6 100644 --- a/examples/flows/standard/describe-image/README.md +++ b/examples/flows/standard/describe-image/README.md @@ -1,5 +1,5 @@ # Describe image flow -A flow that take image input and uses OpenAI GPT-4V tool to describe it. We also added a pass_through node from input to output to demo PromptFlow's ability to output image in both node output and flow output. +A flow that take image input, flip it horizontally and uses OpenAI GPT-4V tool to describe it. Tools used in this flow: - `OpenAI GPT-4V` tool diff --git a/examples/flows/standard/describe-image/flip_image.py b/examples/flows/standard/describe-image/flip_image.py new file mode 100644 index 00000000000..b106b79cd42 --- /dev/null +++ b/examples/flows/standard/describe-image/flip_image.py @@ -0,0 +1,14 @@ +import io +from promptflow import tool +from promptflow.contracts.multimedia import Image +from PIL import Image as PIL_Image + + +@tool +def passthrough(input_image: Image) -> Image: + image_stream = io.BytesIO(input_image) + pil_image = PIL_Image.open(image_stream) + flipped_image = pil_image.transpose(PIL_Image.FLIP_LEFT_RIGHT) + buffer = io.BytesIO() + flipped_image.save(buffer, format="PNG") + return Image(buffer.getvalue(), mime_type="image/png") diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 92ca1bf0bf9..f32c9fcd8fe 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -11,7 +11,7 @@ outputs: reference: ${question_on_image.output} output_image: type: string - reference: ${passthrough.output} + reference: ${flip_image.output} nodes: - name: question_on_image type: custom_llm @@ -22,13 +22,13 @@ nodes: inputs: connection: openai_connection question: ${inputs.question} - test_image: ${passthrough.output} + test_image: ${flip_image.output} model: gpt-4-vision-preview max_tokens: 200 -- name: passthrough +- name: flip_image type: python source: type: code - path: passthrough.py + path: flip_image.py inputs: input_image: ${inputs.input_image} diff --git a/examples/flows/standard/describe-image/passthrough.py b/examples/flows/standard/describe-image/passthrough.py deleted file mode 100644 index b094331d351..00000000000 --- a/examples/flows/standard/describe-image/passthrough.py +++ /dev/null @@ -1,7 +0,0 @@ -from promptflow import tool -from promptflow.contracts.multimedia import Image - - -@tool -def passthrough(input_image: Image) -> Image: - return input_image From 37a7fe79e4db6bb011995bc1af6d53e7bd123bfe Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 21:43:39 +0800 Subject: [PATCH 23/35] Update connection name --- examples/flows/chat/chat-with-image/README.md | 4 ++-- examples/flows/chat/chat-with-image/flow.dag.yaml | 2 +- examples/flows/standard/describe-image/flow.dag.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/flows/chat/chat-with-image/README.md b/examples/flows/chat/chat-with-image/README.md index 55658de64bf..d3fa3a04bfa 100644 --- a/examples/flows/chat/chat-with-image/README.md +++ b/examples/flows/chat/chat-with-image/README.md @@ -27,10 +27,10 @@ Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an " pf connection create --file ../../../connections/openai.yml --set api_key= ``` -Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `openai_connection`. +Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `open_ai_connection`. ```bash # show registered connection -pf connection show --name openai_connection +pf connection show --name open_ai_connection ``` ### 2 Start chatting diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index 8c8a26e80b2..436dae64417 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -23,7 +23,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: chat.jinja2 inputs: - connection: openai_connection + connection: open_ai_connection model: gpt-4-vision-preview max_tokens: 200 chat_history: ${inputs.chat_history} diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index f32c9fcd8fe..70d08485b7a 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -20,7 +20,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: question_on_image.jinja2 inputs: - connection: openai_connection + connection: open_ai_connection question: ${inputs.question} test_image: ${flip_image.output} model: gpt-4-vision-preview From 7936b441076002d468fbb3346376319c3d7f0b02 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Mon, 18 Dec 2023 21:59:28 +0800 Subject: [PATCH 24/35] Fix warning in CI --- docs/how-to-guides/index.md | 1 + docs/how-to-guides/process-image-in-flow.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index 2d83790850b..f47bb98f4f1 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -17,5 +17,6 @@ manage-connections manage-runs set-global-configs develop-a-tool/index +process-image-in-flow faq ``` diff --git a/docs/how-to-guides/process-image-in-flow.md b/docs/how-to-guides/process-image-in-flow.md index 21523ae3878..69a94d32cf8 100644 --- a/docs/how-to-guides/process-image-in-flow.md +++ b/docs/how-to-guides/process-image-in-flow.md @@ -40,7 +40,7 @@ Please note that `path` representation is not supported in Deployment scenario. ## Batch Input data Batch input data containing image can be of 2 formats: 1. The same jsonl format of regular batch input, except that some column may be seriliazed image data or composite data type (dict/list) containing images. The serialized images can only be Url or Base64. E.g. - ```jsonl + ```json {"question": "How many colors are there in the image?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}} {"question": "What's this image about?", "input_image": {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/404.png"}} ``` @@ -52,7 +52,7 @@ Batch input data containing image can be of 2 formats: |----image2.png ``` Content of `input.jsonl` - ```jsonl + ```json {"question": "How many colors are there in the image?", "input_image": {"data:image/png;path": "image1.png"}} {"question": "What's this image about?", "input_image": {"data:image/png;path": "image2.png"}} ``` From 31ffe23433ae0509c47ccd6dc395d4006fe24711 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Tue, 19 Dec 2023 09:18:27 +0800 Subject: [PATCH 25/35] Add missing requirements.txt file --- examples/flows/standard/describe-image/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/flows/standard/describe-image/requirements.txt diff --git a/examples/flows/standard/describe-image/requirements.txt b/examples/flows/standard/describe-image/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d From d9cd6dfad05330b340c748f0e87cc01ea730f274 Mon Sep 17 00:00:00 2001 From: Philip Gao Date: Tue, 19 Dec 2023 16:53:28 +0800 Subject: [PATCH 26/35] gpt_four connections --- .../samples_flows_chat_chat_with_image.yml | 21 ++++++++++++++----- .../samples_flows_standard_describe_image.yml | 21 ++++++++++++++----- examples/README.md | 2 +- .../flows/chat/chat-with-image/flow.dag.yaml | 2 +- .../standard/describe-image/.env.example | 3 +++ .../standard/describe-image/flow.dag.yaml | 2 +- .../readme/ghactions_driver/readme_step.py | 15 +++++++++++++ .../readme_workflow_generate.py | 18 ++++++++++++---- .../step_create_env_gpt4.yml.jinja2 | 11 ++++++++++ ...step_extract_steps_and_run_gpt4.yml.jinja2 | 8 +++---- 10 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 examples/flows/standard/describe-image/.env.example create mode 100644 scripts/readme/ghactions_driver/workflow_steps/step_create_env_gpt4.yml.jinja2 diff --git a/.github/workflows/samples_flows_chat_chat_with_image.yml b/.github/workflows/samples_flows_chat_chat_with_image.yml index 092bb753590..1f83acad9a3 100644 --- a/.github/workflows/samples_flows_chat_chat_with_image.yml +++ b/.github/workflows/samples_flows_chat_chat_with_image.yml @@ -46,8 +46,8 @@ jobs: - name: Refine .env file working-directory: examples/flows/chat/chat-with-image run: | - AOAI_API_KEY=${{ secrets.AOAI_API_KEY_TEST }} - AOAI_API_ENDPOINT=${{ secrets.AOAI_API_ENDPOINT_TEST }} + AOAI_API_KEY=${{ secrets.AOAI_GPT_4V_KEY }} + AOAI_API_ENDPOINT=${{ secrets.AOAI_GPT_4V_ENDPOINT }} AOAI_API_ENDPOINT=$(echo ${AOAI_API_ENDPOINT//\//\\/}) if [[ -e .env.example ]]; then echo "env replacement" @@ -74,15 +74,26 @@ jobs: working-directory: examples/flows/chat/chat-with-image run: | cat bash_script.sh - - name: Run scripts + - name: Run scripts against canary workspace (scheduled runs only) + if: github.event_name == 'schedule' working-directory: examples/flows/chat/chat-with-image run: | - export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} - export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export aoai_api_key=${{secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ secrets.AOAI_GPT_4V_ENDPOINT }} export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_CANARY }} bash bash_script.sh + - name: Run scripts against production workspace + if: github.event_name != 'schedule' + working-directory: examples/flows/chat/chat-with-image + run: | + export aoai_api_key=${{secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ secrets.AOAI_GPT_4V_ENDPOINT }} + export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} + export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} + export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_PROD }} + bash bash_script.sh - name: Pip List for Debug if : ${{ always() }} working-directory: examples/flows/chat/chat-with-image diff --git a/.github/workflows/samples_flows_standard_describe_image.yml b/.github/workflows/samples_flows_standard_describe_image.yml index 77859cced7a..37c7046f07d 100644 --- a/.github/workflows/samples_flows_standard_describe_image.yml +++ b/.github/workflows/samples_flows_standard_describe_image.yml @@ -46,8 +46,8 @@ jobs: - name: Refine .env file working-directory: examples/flows/standard/describe-image run: | - AOAI_API_KEY=${{ secrets.AOAI_API_KEY_TEST }} - AOAI_API_ENDPOINT=${{ secrets.AOAI_API_ENDPOINT_TEST }} + AOAI_API_KEY=${{ secrets.AOAI_GPT_4V_KEY }} + AOAI_API_ENDPOINT=${{ secrets.AOAI_GPT_4V_ENDPOINT }} AOAI_API_ENDPOINT=$(echo ${AOAI_API_ENDPOINT//\//\\/}) if [[ -e .env.example ]]; then echo "env replacement" @@ -74,15 +74,26 @@ jobs: working-directory: examples/flows/standard/describe-image run: | cat bash_script.sh - - name: Run scripts + - name: Run scripts against canary workspace (scheduled runs only) + if: github.event_name == 'schedule' working-directory: examples/flows/standard/describe-image run: | - export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} - export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export aoai_api_key=${{secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ secrets.AOAI_GPT_4V_ENDPOINT }} export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_CANARY }} bash bash_script.sh + - name: Run scripts against production workspace + if: github.event_name != 'schedule' + working-directory: examples/flows/standard/describe-image + run: | + export aoai_api_key=${{secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ secrets.AOAI_GPT_4V_ENDPOINT }} + export test_workspace_sub_id=${{ secrets.TEST_WORKSPACE_SUB_ID }} + export test_workspace_rg=${{ secrets.TEST_WORKSPACE_RG }} + export test_workspace_name=${{ secrets.TEST_WORKSPACE_NAME_PROD }} + bash bash_script.sh - name: Pip List for Debug if : ${{ always() }} working-directory: examples/flows/standard/describe-image diff --git a/examples/README.md b/examples/README.md index 3ef8d3682a7..4df8d0b5b9c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,7 +48,7 @@ | [conditional-flow-for-if-else](flows/standard/conditional-flow-for-if-else/README.md) | [![samples_flows_standard_conditional_flow_for_if_else](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_if_else.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_if_else.yml) | This example is a conditional flow for if-else scenario | | [conditional-flow-for-switch](flows/standard/conditional-flow-for-switch/README.md) | [![samples_flows_standard_conditional_flow_for_switch](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_switch.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_conditional_flow_for_switch.yml) | This example is a conditional flow for switch scenario | | [customer-intent-extraction](flows/standard/customer-intent-extraction/README.md) | [![samples_flows_standard_customer_intent_extraction](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_customer_intent_extraction.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_customer_intent_extraction.yml) | This sample is using OpenAI chat model(ChatGPT/GPT4) to identify customer intent from customer's question | -| [describe-image](flows/standard/describe-image/README.md) | [![samples_flows_standard_describe_image](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml) | A flow that take image input and uses OpenAI GPT-4V tool to describe it | +| [describe-image](flows/standard/describe-image/README.md) | [![samples_flows_standard_describe_image](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_describe_image.yml) | A flow that take image input, flip it horizontally and uses OpenAI GPT-4V tool to describe it | | [flow-with-additional-includes](flows/standard/flow-with-additional-includes/README.md) | [![samples_flows_standard_flow_with_additional_includes](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_additional_includes.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_additional_includes.yml) | User sometimes need to reference some common files or folders, this sample demos how to solve the problem using additional_includes | | [flow-with-symlinks](flows/standard/flow-with-symlinks/README.md) | [![samples_flows_standard_flow_with_symlinks](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_symlinks.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_flow_with_symlinks.yml) | User sometimes need to reference some common files or folders, this sample demos how to solve the problem using symlinks | | [gen-docstring](flows/standard/gen-docstring/README.md) | [![samples_flows_standard_gen_docstring](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_gen_docstring.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_gen_docstring.yml) | This example can help you automatically generate Python code's docstring and return the modified code | diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index 436dae64417..bcfd60c770f 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -23,7 +23,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: chat.jinja2 inputs: - connection: open_ai_connection + connection: aoai_gpt4v_connection model: gpt-4-vision-preview max_tokens: 200 chat_history: ${inputs.chat_history} diff --git a/examples/flows/standard/describe-image/.env.example b/examples/flows/standard/describe-image/.env.example new file mode 100644 index 00000000000..4be9648d738 --- /dev/null +++ b/examples/flows/standard/describe-image/.env.example @@ -0,0 +1,3 @@ +AZURE_OPENAI_API_KEY= +AZURE_OPENAI_API_BASE= +AZURE_OPENAI_API_VERSION=2023-03-15-preview diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 70d08485b7a..3c74955e9ae 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -20,7 +20,7 @@ nodes: tool: promptflow.tools.openai_gpt4v.OpenAI.chat path: question_on_image.jinja2 inputs: - connection: open_ai_connection + connection: aoai_gpt4v_connection question: ${inputs.question} test_image: ${flip_image.output} model: gpt-4-vision-preview diff --git a/scripts/readme/ghactions_driver/readme_step.py b/scripts/readme/ghactions_driver/readme_step.py index a03eaf5dc99..5db0b9ef269 100644 --- a/scripts/readme/ghactions_driver/readme_step.py +++ b/scripts/readme/ghactions_driver/readme_step.py @@ -139,6 +139,17 @@ def get_workflow_step(self) -> str: {"step_name": self.workflow_name, "working_dir": ReadmeSteps.working_dir} ) return content + +class CreateEnvGPTFour(Step): + def __init__(self) -> None: + Step.__init__(self, "Refine .env file") + + def get_workflow_step(self) -> str: + template = Step.get_workflow_template("step_create_env_gpt4.yml.jinja2") + content = template.render( + {"step_name": self.workflow_name, "working_dir": ReadmeSteps.working_dir} + ) + return content class CreateAoaiFromEnv(Step): @@ -194,6 +205,10 @@ def get_length() -> int: @staticmethod def create_env() -> Step: return ReadmeSteps.remember_step(CreateEnv()) + + @staticmethod + def create_env_gpt4() -> Step: + return ReadmeSteps.remember_step(CreateEnvGPTFour()) @staticmethod def yml_create_aoai(yaml_name: str) -> Step: diff --git a/scripts/readme/ghactions_driver/readme_workflow_generate.py b/scripts/readme/ghactions_driver/readme_workflow_generate.py index 3b7c9075e34..8e1e60ea7f5 100644 --- a/scripts/readme/ghactions_driver/readme_workflow_generate.py +++ b/scripts/readme/ghactions_driver/readme_workflow_generate.py @@ -29,9 +29,16 @@ def write_readme_workflow(readme_path, output_telemetry=Telemetry()): ) ReadmeSteps.install_dependencies() ReadmeSteps.install_dev_dependencies() - ReadmeSteps.create_env() - if workflow_name.endswith("pdf"): - ReadmeSteps.env_create_aoai("chat_with_pdf_custom_connection") + if ( + workflow_name.endswith("flows_chat_chat_with_image") + or workflow_name.endswith("flows_standard_describe_image") + ): + ReadmeSteps.create_env_gpt4 () + ReadmeSteps.env_create_aoai("aoai_gpt4v_connection") + else: + ReadmeSteps.create_env() + if workflow_name.endswith("pdf"): + ReadmeSteps.env_create_aoai("chat_with_pdf_custom_connection") ReadmeSteps.create_run_yaml() if ( workflow_name.endswith("flows_standard_basic_with_builtin_llm") @@ -41,7 +48,10 @@ def write_readme_workflow(readme_path, output_telemetry=Telemetry()): ): ReadmeSteps.yml_create_aoai("examples/connections/azure_openai.yml") ReadmeSteps.azure_login() - if workflow_name.endswith("flows_standard_summarizing_film_with_autogpt"): + if ( + workflow_name.endswith("flows_chat_chat_with_image") + or workflow_name.endswith("flows_standard_describe_image") + ): ReadmeSteps.extract_steps_and_run_gpt_four() else: ReadmeSteps.extract_steps_and_run() diff --git a/scripts/readme/ghactions_driver/workflow_steps/step_create_env_gpt4.yml.jinja2 b/scripts/readme/ghactions_driver/workflow_steps/step_create_env_gpt4.yml.jinja2 new file mode 100644 index 00000000000..904eb9ee409 --- /dev/null +++ b/scripts/readme/ghactions_driver/workflow_steps/step_create_env_gpt4.yml.jinja2 @@ -0,0 +1,11 @@ +- name: {{ step_name }} + working-directory: {{ working_dir }} + run: | + AOAI_API_KEY=${{ '{{' }} secrets.AOAI_GPT_4V_KEY }} + AOAI_API_ENDPOINT=${{ '{{' }} secrets.AOAI_GPT_4V_ENDPOINT }} + AOAI_API_ENDPOINT=$(echo ${AOAI_API_ENDPOINT//\//\\/}) + if [[ -e .env.example ]]; then + echo "env replacement" + sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example + mv .env.example .env + fi diff --git a/scripts/readme/ghactions_driver/workflow_steps/step_extract_steps_and_run_gpt4.yml.jinja2 b/scripts/readme/ghactions_driver/workflow_steps/step_extract_steps_and_run_gpt4.yml.jinja2 index b76dd517409..be7300279a1 100644 --- a/scripts/readme/ghactions_driver/workflow_steps/step_extract_steps_and_run_gpt4.yml.jinja2 +++ b/scripts/readme/ghactions_driver/workflow_steps/step_extract_steps_and_run_gpt4.yml.jinja2 @@ -10,8 +10,8 @@ if: github.event_name == 'schedule' working-directory: {{ working_dir }} run: | - export aoai_api_key=${{ '{{' }}secrets.AOAI_API_KEY_TEST }} - export aoai_api_endpoint=${{ '{{' }} secrets.AOAI_API_ENDPOINT_TEST }} + export aoai_api_key=${{ '{{' }}secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ '{{' }} secrets.AOAI_GPT_4V_ENDPOINT }} export test_workspace_sub_id=${{ '{{' }} secrets.TEST_WORKSPACE_SUB_ID }} export test_workspace_rg=${{ '{{' }} secrets.TEST_WORKSPACE_RG }} export test_workspace_name=${{ '{{' }} secrets.TEST_WORKSPACE_NAME_CANARY }} @@ -20,8 +20,8 @@ if: github.event_name != 'schedule' working-directory: {{ working_dir }} run: | - export aoai_api_key=${{ '{{' }}secrets.AOAI_API_KEY_TEST }} - export aoai_api_endpoint=${{ '{{' }} secrets.AOAI_API_ENDPOINT_TEST }} + export aoai_api_key=${{ '{{' }}secrets.AOAI_GPT_4V_KEY }} + export aoai_api_endpoint=${{ '{{' }} secrets.AOAI_GPT_4V_ENDPOINT }} export test_workspace_sub_id=${{ '{{' }} secrets.TEST_WORKSPACE_SUB_ID }} export test_workspace_rg=${{ '{{' }} secrets.TEST_WORKSPACE_RG }} export test_workspace_name=${{ '{{' }} secrets.TEST_WORKSPACE_NAME_PROD }} From 57287e216672006914267e08cbe7c2de0be145eb Mon Sep 17 00:00:00 2001 From: Philip Gao Date: Tue, 19 Dec 2023 16:57:57 +0800 Subject: [PATCH 27/35] Fix connection --- .github/workflows/samples_flows_chat_chat_with_image.yml | 8 ++++++++ .../workflows/samples_flows_standard_describe_image.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/samples_flows_chat_chat_with_image.yml b/.github/workflows/samples_flows_chat_chat_with_image.yml index 1f83acad9a3..bdf35772a39 100644 --- a/.github/workflows/samples_flows_chat_chat_with_image.yml +++ b/.github/workflows/samples_flows_chat_chat_with_image.yml @@ -54,6 +54,14 @@ jobs: sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example mv .env.example .env fi + - name: Create AOAI Connection from ENV file + working-directory: examples/flows/chat/chat-with-image + run: | + if [[ -e .env ]]; then + pf connection create --file .env --name aoai_gpt4v_connection + pf connection list + fi + - name: Create run.yml working-directory: examples/flows/chat/chat-with-image run: | diff --git a/.github/workflows/samples_flows_standard_describe_image.yml b/.github/workflows/samples_flows_standard_describe_image.yml index 37c7046f07d..644940c1871 100644 --- a/.github/workflows/samples_flows_standard_describe_image.yml +++ b/.github/workflows/samples_flows_standard_describe_image.yml @@ -54,6 +54,14 @@ jobs: sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example mv .env.example .env fi + - name: Create AOAI Connection from ENV file + working-directory: examples/flows/standard/describe-image + run: | + if [[ -e .env ]]; then + pf connection create --file .env --name aoai_gpt4v_connection + pf connection list + fi + - name: Create run.yml working-directory: examples/flows/standard/describe-image run: | From 8f84c7e2bedded3d6d173a29095602d1bda400b2 Mon Sep 17 00:00:00 2001 From: Philip Gao Date: Tue, 19 Dec 2023 17:14:39 +0800 Subject: [PATCH 28/35] flake8 fix --- .../readme/ghactions_driver/readme_step.py | 24 ++++++++++++++----- .../readme_workflow_generate.py | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/scripts/readme/ghactions_driver/readme_step.py b/scripts/readme/ghactions_driver/readme_step.py index 5db0b9ef269..56febfc4645 100644 --- a/scripts/readme/ghactions_driver/readme_step.py +++ b/scripts/readme/ghactions_driver/readme_step.py @@ -139,7 +139,8 @@ def get_workflow_step(self) -> str: {"step_name": self.workflow_name, "working_dir": ReadmeSteps.working_dir} ) return content - + + class CreateEnvGPTFour(Step): def __init__(self) -> None: Step.__init__(self, "Refine .env file") @@ -205,7 +206,7 @@ def get_length() -> int: @staticmethod def create_env() -> Step: return ReadmeSteps.remember_step(CreateEnv()) - + @staticmethod def create_env_gpt4() -> Step: return ReadmeSteps.remember_step(CreateEnvGPTFour()) @@ -306,17 +307,28 @@ def write_workflow( # markdown filename has some exceptions, special handle here if "chat_with_pdf" in workflow_name: readme_name = "chat-with-pdf.md" - elif "fine_tuning_evaluation_promptflow_quality_improvement" in workflow_name: + elif ( + "fine_tuning_evaluation_promptflow_quality_improvement" in workflow_name + ): readme_name = "promptflow-quality-improvement.md" else: readme_name = "README.md" - readme_path = Path(ReadmeStepsManage.git_base_dir()) / ReadmeSteps.working_dir / readme_name + readme_path = ( + Path(ReadmeStepsManage.git_base_dir()) + / ReadmeSteps.working_dir + / readme_name + ) # local import to avoid circular import from .resource_resolver import resolve_tutorial_resource - path_filter = resolve_tutorial_resource(workflow_name, readme_path.resolve()) + path_filter = resolve_tutorial_resource( + workflow_name, readme_path.resolve() + ) else: - if "flow_with_additional_includes" in workflow_name or "flow_with_symlinks" in workflow_name: + if ( + "flow_with_additional_includes" in workflow_name + or "flow_with_symlinks" in workflow_name + ): # these two flows have dependencies on flow web-classification # so corresponding workflows should also listen to changes in web-classification path_filter = ( diff --git a/scripts/readme/ghactions_driver/readme_workflow_generate.py b/scripts/readme/ghactions_driver/readme_workflow_generate.py index 8e1e60ea7f5..f35e1b03a75 100644 --- a/scripts/readme/ghactions_driver/readme_workflow_generate.py +++ b/scripts/readme/ghactions_driver/readme_workflow_generate.py @@ -33,7 +33,7 @@ def write_readme_workflow(readme_path, output_telemetry=Telemetry()): workflow_name.endswith("flows_chat_chat_with_image") or workflow_name.endswith("flows_standard_describe_image") ): - ReadmeSteps.create_env_gpt4 () + ReadmeSteps.create_env_gpt4() ReadmeSteps.env_create_aoai("aoai_gpt4v_connection") else: ReadmeSteps.create_env() From 7a1bf215ab8a86aa5d445702370adf3488452aa5 Mon Sep 17 00:00:00 2001 From: Philip Gao Date: Tue, 19 Dec 2023 17:30:32 +0800 Subject: [PATCH 29/35] Fix chat with image --- examples/flows/chat/chat-with-image/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/flows/chat/chat-with-image/README.md b/examples/flows/chat/chat-with-image/README.md index d3fa3a04bfa..4b4cf01df17 100644 --- a/examples/flows/chat/chat-with-image/README.md +++ b/examples/flows/chat/chat-with-image/README.md @@ -24,13 +24,13 @@ Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an " ```bash # Override keys with --set to avoid yaml file changes -pf connection create --file ../../../connections/openai.yml --set api_key= +pf connection create --file ../../../connections/openai.yml --set api_key= api_base= name=aoai_gpt4v_connection api_version=2023-03-15-preview ``` -Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `open_ai_connection`. +Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `aoai_gpt4v_connection`. ```bash # show registered connection -pf connection show --name open_ai_connection +pf connection show --name aoai_gpt4v_connection ``` ### 2 Start chatting @@ -41,7 +41,9 @@ pf flow test --flow . # run chat flow with new question pf flow test --flow . --inputs question='["How many colors can you see?", {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"}]' +``` +```sh # start a interactive chat session in CLI pf flow test --flow . --interactive From 9339ddd6201b0856e67e5a91f302932bb19930f9 Mon Sep 17 00:00:00 2001 From: Philip Gao Date: Tue, 19 Dec 2023 17:34:34 +0800 Subject: [PATCH 30/35] Fix Connection base yaml --- examples/flows/chat/chat-with-image/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flows/chat/chat-with-image/README.md b/examples/flows/chat/chat-with-image/README.md index 4b4cf01df17..745635bf2ef 100644 --- a/examples/flows/chat/chat-with-image/README.md +++ b/examples/flows/chat/chat-with-image/README.md @@ -24,7 +24,7 @@ Go to "Prompt flow" "Connections" tab. Click on "Create" button, and create an " ```bash # Override keys with --set to avoid yaml file changes -pf connection create --file ../../../connections/openai.yml --set api_key= api_base= name=aoai_gpt4v_connection api_version=2023-03-15-preview +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=aoai_gpt4v_connection api_version=2023-03-15-preview ``` Note in [flow.dag.yaml](flow.dag.yaml) we are using connection named `aoai_gpt4v_connection`. From 0984a3efcd2aa5d080d7cd9512b28cba8d0d3bd7 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Wed, 20 Dec 2023 12:22:36 +0800 Subject: [PATCH 31/35] Update chat with image --- .../flows/chat/chat-with-image/flow.dag.yaml | 10 +++++----- .../standard/describe-image/flow.dag.yaml | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/flows/chat/chat-with-image/flow.dag.yaml b/examples/flows/chat/chat-with-image/flow.dag.yaml index bcfd60c770f..a145bb385f9 100644 --- a/examples/flows/chat/chat-with-image/flow.dag.yaml +++ b/examples/flows/chat/chat-with-image/flow.dag.yaml @@ -7,8 +7,8 @@ inputs: question: type: list default: - - How many colors can you see? - - {"data:image/png;url": "https://developer.microsoft.com/_devcom/images/logo-ms-social.png"} + - data:image/png;url: https://images.idgesg.net/images/article/2019/11/edge-browser-logo_microsoft-100816808-large.jpg + - How many colors can you see? is_chat_input: true outputs: answer: @@ -20,11 +20,11 @@ nodes: type: custom_llm source: type: package_with_prompt - tool: promptflow.tools.openai_gpt4v.OpenAI.chat + tool: promptflow.tools.aoai_gpt4v.AzureOpenAI.chat path: chat.jinja2 inputs: connection: aoai_gpt4v_connection - model: gpt-4-vision-preview - max_tokens: 200 + deployment_name: gpt-4v + max_tokens: 512 chat_history: ${inputs.chat_history} question: ${inputs.question} diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 3c74955e9ae..44aa6098be7 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -13,22 +13,22 @@ outputs: type: string reference: ${flip_image.output} nodes: +- name: flip_image + type: python + source: + type: code + path: flip_image.py + inputs: + input_image: ${inputs.input_image} - name: question_on_image type: custom_llm source: type: package_with_prompt - tool: promptflow.tools.openai_gpt4v.OpenAI.chat + tool: promptflow.tools.aoai_gpt4v.AzureOpenAI.chat path: question_on_image.jinja2 inputs: connection: aoai_gpt4v_connection + deployment_name: gpt-4v + max_tokens: 512 question: ${inputs.question} test_image: ${flip_image.output} - model: gpt-4-vision-preview - max_tokens: 200 -- name: flip_image - type: python - source: - type: code - path: flip_image.py - inputs: - input_image: ${inputs.input_image} From 4ed09fc6f3bf7575462a45559957c45fd7599e81 Mon Sep 17 00:00:00 2001 From: Ming Gu Date: Wed, 20 Dec 2023 13:59:30 +0800 Subject: [PATCH 32/35] Add tool requirement --- examples/flows/chat/chat-with-image/requirements.txt | 2 ++ examples/flows/standard/describe-image/requirements.txt | 2 ++ examples/requirements.txt | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/flows/chat/chat-with-image/requirements.txt b/examples/flows/chat/chat-with-image/requirements.txt index e69de29bb2d..34d068f5f1c 100644 --- a/examples/flows/chat/chat-with-image/requirements.txt +++ b/examples/flows/chat/chat-with-image/requirements.txt @@ -0,0 +1,2 @@ +promptflow +promptflow-tools \ No newline at end of file diff --git a/examples/flows/standard/describe-image/requirements.txt b/examples/flows/standard/describe-image/requirements.txt index e69de29bb2d..34d068f5f1c 100644 --- a/examples/flows/standard/describe-image/requirements.txt +++ b/examples/flows/standard/describe-image/requirements.txt @@ -0,0 +1,2 @@ +promptflow +promptflow-tools \ No newline at end of file diff --git a/examples/requirements.txt b/examples/requirements.txt index 82bc2466acb..21832de3282 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -1,4 +1,4 @@ promptflow[azure] -promptflow-tools==1.0.0 +promptflow-tools python-dotenv bs4 From 8ee6203117d8b3dba7e94eb40b1267e9c54e7763 Mon Sep 17 00:00:00 2001 From: Zhengfei Wang Date: Wed, 20 Dec 2023 14:50:57 +0800 Subject: [PATCH 33/35] fix: wrong deployment name --- examples/flows/standard/describe-image/flow.dag.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flows/standard/describe-image/flow.dag.yaml b/examples/flows/standard/describe-image/flow.dag.yaml index 44aa6098be7..35d9e50d58a 100644 --- a/examples/flows/standard/describe-image/flow.dag.yaml +++ b/examples/flows/standard/describe-image/flow.dag.yaml @@ -28,7 +28,7 @@ nodes: path: question_on_image.jinja2 inputs: connection: aoai_gpt4v_connection - deployment_name: gpt-4v + deployment_name: gpt-4 max_tokens: 512 question: ${inputs.question} test_image: ${flip_image.output} From f02f535aba053675d336b163bf31420eabf87332 Mon Sep 17 00:00:00 2001 From: Zhengfei Wang Date: Wed, 20 Dec 2023 15:10:20 +0800 Subject: [PATCH 34/35] fix: make .env as a YAML --- .../workflows/samples_flows_standard_describe_image.yml | 6 ------ examples/flows/standard/describe-image/.env.example | 9 ++++++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/samples_flows_standard_describe_image.yml b/.github/workflows/samples_flows_standard_describe_image.yml index 644940c1871..9ccf38096f2 100644 --- a/.github/workflows/samples_flows_standard_describe_image.yml +++ b/.github/workflows/samples_flows_standard_describe_image.yml @@ -25,12 +25,6 @@ jobs: uses: actions/setup-python@v4 with: python-version: "3.9" - - name: Generate config.json for canary workspace (scheduled runs only) - if: github.event_name == 'schedule' - run: echo '${{ secrets.TEST_WORKSPACE_CONFIG_JSON_CANARY }}' > ${{ github.workspace }}/examples/config.json - - name: Generate config.json for production workspace - if: github.event_name != 'schedule' - run: echo '${{ secrets.EXAMPLE_WORKSPACE_CONFIG_JSON_PROD }}' > ${{ github.workspace }}/examples/config.json - name: Prepare requirements working-directory: examples run: | diff --git a/examples/flows/standard/describe-image/.env.example b/examples/flows/standard/describe-image/.env.example index 4be9648d738..97c164a1bb2 100644 --- a/examples/flows/standard/describe-image/.env.example +++ b/examples/flows/standard/describe-image/.env.example @@ -1,3 +1,6 @@ -AZURE_OPENAI_API_KEY= -AZURE_OPENAI_API_BASE= -AZURE_OPENAI_API_VERSION=2023-03-15-preview +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json +name: aoai_gpt4v_connection +type: azure_open_ai +api_key: "" +api_base: "" +api_type: "azure" From fa0f995b9709d7ec712fc3de88108e90abc2da6f Mon Sep 17 00:00:00 2001 From: Zhengfei Wang Date: Wed, 20 Dec 2023 15:13:46 +0800 Subject: [PATCH 35/35] use YAML suffix --- .../workflows/samples_flows_standard_describe_image.yml | 8 +++----- examples/flows/standard/describe-image/.env.example | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/samples_flows_standard_describe_image.yml b/.github/workflows/samples_flows_standard_describe_image.yml index 9ccf38096f2..473e116f33c 100644 --- a/.github/workflows/samples_flows_standard_describe_image.yml +++ b/.github/workflows/samples_flows_standard_describe_image.yml @@ -46,15 +46,13 @@ jobs: if [[ -e .env.example ]]; then echo "env replacement" sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example - mv .env.example .env + mv .env.example gpt4v.yaml fi - name: Create AOAI Connection from ENV file working-directory: examples/flows/standard/describe-image run: | - if [[ -e .env ]]; then - pf connection create --file .env --name aoai_gpt4v_connection - pf connection list - fi + pf connection create --file gpt4v.yaml --name aoai_gpt4v_connection + pf connection list - name: Create run.yml working-directory: examples/flows/standard/describe-image diff --git a/examples/flows/standard/describe-image/.env.example b/examples/flows/standard/describe-image/.env.example index 97c164a1bb2..3f7ca79ec03 100644 --- a/examples/flows/standard/describe-image/.env.example +++ b/examples/flows/standard/describe-image/.env.example @@ -1,6 +1,6 @@ $schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json name: aoai_gpt4v_connection type: azure_open_ai -api_key: "" -api_base: "" -api_type: "azure" +api_key: +api_base: +api_type: azure