From 709e56a3919569a72c5f468a952e472bad9626aa Mon Sep 17 00:00:00 2001 From: yalu4 Date: Tue, 9 Jan 2024 14:40:46 +0800 Subject: [PATCH 001/112] outline --- docs/how-to-guides/construct-test-data.md | 14 +++++ docs/how-to-guides/index.md | 1 + .../construct_test_data_flow/flow.dag.yaml | 0 examples/test_data_gen/doc_split.py | 33 +++++++++++ examples/test_data_gen/pipeline/conda.yml | 8 +++ .../test_data_gen/pipeline/document_split.yml | 25 +++++++++ .../pipeline/document_split_src/split.py | 56 +++++++++++++++++++ .../test_data_gen/pipeline/submit_pipeline.py | 44 +++++++++++++++ 8 files changed, 181 insertions(+) create mode 100644 docs/how-to-guides/construct-test-data.md create mode 100644 examples/test_data_gen/construct_test_data_flow/flow.dag.yaml create mode 100644 examples/test_data_gen/doc_split.py create mode 100644 examples/test_data_gen/pipeline/conda.yml create mode 100644 examples/test_data_gen/pipeline/document_split.yml create mode 100644 examples/test_data_gen/pipeline/document_split_src/split.py create mode 100644 examples/test_data_gen/pipeline/submit_pipeline.py diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md new file mode 100644 index 00000000000..0b9f7597447 --- /dev/null +++ b/docs/how-to-guides/construct-test-data.md @@ -0,0 +1,14 @@ +# How to construct test data based on documents + + +## Data preprocess + +## Build your test data generation flow + +## Deal with big data + +## Use generated test data in flow/experiment +### Local story in flow +### Protal story in flow +### Local story in experiment +### Protal story in experiment \ No newline at end of file diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index f47bb98f4f1..3f41006f4a6 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -18,5 +18,6 @@ manage-runs set-global-configs develop-a-tool/index process-image-in-flow +construct-test-data faq ``` diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/doc_split.py b/examples/test_data_gen/doc_split.py new file mode 100644 index 00000000000..2bfedb462d8 --- /dev/null +++ b/examples/test_data_gen/doc_split.py @@ -0,0 +1,33 @@ +import json +import os +import typing as t +from datetime import datetime + +from llama_index import SimpleDirectoryReader + +try: + from llama_index.node_parser import SimpleNodeParser + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + + +def split_doc(input_file_path: str, output_file_path: str, chunk_size: int): + # load docs + documents = SimpleDirectoryReader(input_file_path).load_data() + # Convert documents into nodes + node_parser = SimpleNodeParser.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) + documents = t.cast(t.List[LlamaindexDocument], documents) + document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) + + jsonl_str = "" + for doc in document_nodes: + json_dict = {"document_node": doc.to_json()} + jsonl_str += json.dumps(json_dict) + "\n" + + cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") + with open(os.path.join(output_file_path, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/pipeline/conda.yml b/examples/test_data_gen/pipeline/conda.yml new file mode 100644 index 00000000000..d6151f619be --- /dev/null +++ b/examples/test_data_gen/pipeline/conda.yml @@ -0,0 +1,8 @@ +name: doc_split_conda_env +channels: + - defaults +dependencies: + - python=3.10.12 + - pip=23.2.1 + - pip: + - llama_index diff --git a/examples/test_data_gen/pipeline/document_split.yml b/examples/test_data_gen/pipeline/document_split.yml new file mode 100644 index 00000000000..bc81e007e21 --- /dev/null +++ b/examples/test_data_gen/pipeline/document_split.yml @@ -0,0 +1,25 @@ +$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json +type: command + +name: doc_split_0 +display_name: docSplit0 +version: 3 + +inputs: + doc_split_0_input: + type: uri_folder + doc_split_0_chunk_size: + type: integer + +outputs: + doc_split_0_output: + type: uri_folder + +code: ./document_split_src + +environment: + conda_file: ./conda.yml + image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 + +command: >- + python split.py --doc_split_0_input ${{inputs.doc_split_0_input}} --doc_split_0_chunk_size ${{inputs.doc_split_0_chunk_size}} --doc_split_0_output ${{outputs.doc_split_0_output}} diff --git a/examples/test_data_gen/pipeline/document_split_src/split.py b/examples/test_data_gen/pipeline/document_split_src/split.py new file mode 100644 index 00000000000..4d1d1cf282b --- /dev/null +++ b/examples/test_data_gen/pipeline/document_split_src/split.py @@ -0,0 +1,56 @@ +import argparse +import json +import os +import typing as t +from datetime import datetime + +from llama_index import SimpleDirectoryReader + +try: + from llama_index.node_parser import SimpleNodeParser + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + +parser = argparse.ArgumentParser() +parser.add_argument("--doc_split_0_input", type=str) +parser.add_argument("--doc_split_0_chunk_size", type=int) +parser.add_argument("--doc_split_0_output", type=str) + + +args = parser.parse_args() + +print("doc_split_0_input path: %s" % args.doc_split_0_input) +print(f"doc_split_0_chunk_size: {type(args.doc_split_0_chunk_size)}: {args.doc_split_0_chunk_size}") +print("doc_split_0_output path: %s" % args.doc_split_0_output) + +print("files in input path: ") +arr = os.listdir(args.doc_split_0_input) +print(arr) + +for filename in arr: + print("reading file: %s ..." % filename) + with open(os.path.join(args.doc_split_0_input, filename), "r") as handle: + print(handle.read()) + +# load docs +documents = SimpleDirectoryReader(args.doc_split_0_input).load_data() +# Convert documents into nodes +node_parser = SimpleNodeParser.from_defaults( + chunk_size=args.doc_split_0_chunk_size, chunk_overlap=0, include_metadata=True +) +documents = t.cast(t.List[LlamaindexDocument], documents) +document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) + +jsonl_str = "" +for doc in document_nodes: + json_dict = {"document_node": doc.to_json()} + jsonl_str += json.dumps(json_dict) + "\n" + + +cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") +with open(os.path.join(args.doc_split_0_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/pipeline/submit_pipeline.py b/examples/test_data_gen/pipeline/submit_pipeline.py new file mode 100644 index 00000000000..27e422103b0 --- /dev/null +++ b/examples/test_data_gen/pipeline/submit_pipeline.py @@ -0,0 +1,44 @@ +from azure.ai.ml import Input, MLClient, dsl, load_component +from azure.identity import DefaultAzureCredential + +subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" +resource_group = "promptflow" +workspace_name = "" + +credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) +ml_client = MLClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group, + workspace_name=workspace_name, +) + + +flow_component = load_component("D:\\proj\\PromptFlow\\docs\\evaluation\\examples\\test_data_gen_flow_2\\flow.dag.yaml") + +doc_component = load_component("D:\\proj\\PromptFlow\\docs\\evaluation\\data_gen_poc\\pipeline\\document_split.yml") + + +data_input = Input(path="D:\\proj\\PromptFlow\\docs\\evaluation\\data_gen_poc\\documents", type="uri_folder") + + +@dsl.pipeline +def pipeline_func_with_flow(data): + document_node = doc_component(doc_split_0_input=data, doc_split_0_chunk_size=1024) + document_node.compute = "cpu-cluster" + + flow_node = flow_component( + data=document_node.outputs.doc_split_0_output, + document_node="${data.document_node}", + connections={ + "generate_test_data": {"connection": "azure_open_ai_connection"}, + }, + ) + flow_node.compute = "cpu-cluster" + flow_node.mini_batch_size = 2 + flow_node.max_concurrency_per_instance = 2 + + +pipeline_with_flow = pipeline_func_with_flow(data=data_input) + +ml_client.jobs.create_or_update(pipeline_with_flow) From 8378cd7a5ff0f9919d40c91f3ea3dd96f8e2fd2a Mon Sep 17 00:00:00 2001 From: yalu4 Date: Tue, 9 Jan 2024 17:27:15 +0800 Subject: [PATCH 002/112] update --- docs/how-to-guides/construct-test-data.md | 25 +++++++++ .../temp-to-delete/to_consider_doc_split.png | Bin 0 -> 112092 bytes .../test_data_gen/pipeline/submit_pipeline.py | 49 ++++++++++++------ 3 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 docs/how-to-guides/temp-to-delete/to_consider_doc_split.png diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index 0b9f7597447..67957c83375 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -2,12 +2,37 @@ ## Data preprocess +### local +Run doc_split script. +Interface: +- documents folder path +- output file path +- chunk_size +- ?? do we need to provide test size? How to combine with the flow? How to instruct users to set their own chunk size? + +?? what if the documents folder is in azure blob folder? Or any other possibility? +![Consider](./temp-to-delete/to_consider_doc_split.png) + +### portal +Locally run doc_split script. Then upload the generated doc nodes jsonl file to portal as a data asset. +-> In this way, we should at least consider how user can do both process in local and cloud. +local: read folder from remote site, then upload to cloud. +portal: process and split directly in portal. ## Build your test data generation flow +Interface: +- question type +- test distribution +- document chunk +- llm connection + ## Deal with big data +Use pipeline to run test data gen. Run sample script to submit your pipeline. ## Use generated test data in flow/experiment +For local extension, we will provide a data.jsonl file. +For portal, the generated test data needs to be registered as a data asset in order to be used in experiment. ### Local story in flow ### Protal story in flow ### Local story in experiment diff --git a/docs/how-to-guides/temp-to-delete/to_consider_doc_split.png b/docs/how-to-guides/temp-to-delete/to_consider_doc_split.png new file mode 100644 index 0000000000000000000000000000000000000000..5b85f4200c642475cc6c50054c2ca00c48aa0f8f GIT binary patch literal 112092 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


-t0d1g&^scSrHw5EvEv5#-{U!wfAu zQQd=iby?vRzgN{QSjq=J4N{nPOpc0d}MX2g4|4^-I+2xu&I* zy3<0&XIKdD2~uh?HT`~XcvTcFW~qhQX4DjU!!)22m( z*fJsf`{Yy-00kKVk(|!-mcG2TU-qr&Y!{0Yr0HD2wnSK>=-KdDHSN(9JcDkEI zk3aNSd1&QMfm;OgmK-f48*OxZpZks3M=Yh;s>Z#KXnPEk*z%WwmGp{3?eFy}J1g!V z6Yrv@9y$Tx-P%zcKsL5c>;C1QCS;p@Yj(bwl%}<1$}I@+f&ck#CxkMHa?9b=K;VE= z@HHnejY~QKF#q_Hi|NK6+a$m(6!QCJNkXEdYv}XyI<{5>D@EK*@O+{wNf_{4fq(ep zu){>F-3dX2Wuc7s0Go>Fbv;j=hLBbeq-}%nNU~Q*ltFwNW$rpIB^w)CYD@O94iu1$ zIz;twiCIOj6HHD_f#=lE+ubf|mi<9j_g()!#mS&GfU3-Q6RNPCf-9$pU&d3&?ufx|TNSDk)H;>}b%M0^yw%!!)FErP?&=SQ3$ zf6IBf`D !n}|Qf0|K1ChbK}wQSHVa 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


-t0d1g&^scSrHw5EvEv5#-{U!wfAu zQQd=iby?vRzgN{QSjq=J4N{nPOpc0d}MX2g4|4^-I+2xu&I* zy3<0&XIKdD2~uh?HT`~XcvTcFW~qhQX4DjU!!)22m( z*fJsf`{Yy-00kKVk(|!-mcG2TU-qr&Y!{0Yr0HD2wnSK>=-KdDHSN(9JcDkEI zk3aNSd1&QMfm;OgmK-f48*OxZpZks3M=Yh;s>Z#KXnPEk*z%WwmGp{3?eFy}J1g!V z6Yrv@9y$Tx-P%zcKsL5c>;C1QCS;p@Yj(bwl%}<1$}I@+f&ck#CxkMHa?9b=K;VE= z@HHnejY~QKF#q_Hi|NK6+a$m(6!QCJNkXEdYv}XyI<{5>D@EK*@O+{wNf_{4fq(ep zu){>F-3dX2Wuc7s0Go>Fbv;j=hLBbeq-}%nNU~Q*ltFwNW$rpIB^w)CYD@O94iu1$ zIz;twiCIOj6HHD_f#=lE+ubf|mi<9j_g()!#mS&GfU3-Q6RNPCf-9$pU&d3&?ufx|TNSDk)H;>}b%M0^yw%!!)FErP?&=SQ3$ zf6IBf`D !n}|Qf0|K1ChbK}wQSHVa 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

ylZTev?ZEe(R_OE{C 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 A4FCWD literal 0 HcmV?d00001 diff --git a/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md new file mode 100644 index 00000000000..1efe6e6ff92 --- /dev/null +++ b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md @@ -0,0 +1,114 @@ +# Develop promptflow copilot + +In this tutorial, we will show you how to develop a RAG based copilot step by step using the toolsets provided by Azure Machine Learning promptflow. Specifically, we will cover the following topics: +- How to initialize a RAG based copilot flow from AzureML workspace portal +- How to generate synthetic test data for the copilot +- How to evaluate your copilot with test data +- How to improve your copilot flow +- How to deploy your copilot flow as a web service +- How to continuously monitor your copilot flow + +We will develop copilot for promptflow as example in this tutorial, you can develop your own copilot following the similar steps. + +## Prerequisites + +- An Azure subscription. If you don't have an Azure subscription, create a free account before you begin +- An Azure Machine Learning workspace. If you don't have a workspace, create one before you begin +- Azure OpenAI connection or OpenAI connection +- Azure AI Search connection + +## Step 1: Initialize a RAG based copilot flow + +Firstly, clone the promptflow repository to your local machine. Then, in your Azure Machine Learning workspace, create vector index using the document files inside `./docs` folder. For detailed instructions about create vector index, you can reference the document [here](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-create-vector-index?view=azureml-api-2#create-a-vector-index-by-using-machine-learning-studio). + +After the vector index created, an example prompt flow will be automatically generated in the workspace. You can find the example prompt flow's link in the vector index's detail page. The example flow is a typical RAG based copilot flow, it will be a good start point for use to develop our copilot. + +This is how the example flow looks like: +![example-flow](example-flow.png) + +With some minor configuration, you can open the chat panel and directly chat with your copilot to see how good it works. + +![chat-panel](chat-panel.png) + +### Tips + +``` +Prepare your data carefully. The quality of the data will directly affect the performance of the copilot. Promptflow had prepared rich and insightful document in the `./docs` folder, so we vectorized it as the context for our copilot. Meanwhile, we filter out the image files which cannot be vectorized and some markdown files that contains no meaningful information. +``` + +## Step 2: Generate synthetic test data + +To ensure the quality of the promptflow copilot, we need to test it on a large set of data. The test data could be from the real user cases, like questions posted on stackoverflow. However, the test data from real user cases is usually lack of amount and comprehensiveness. Therefore, we need to generate synthetic test data to cover more scenarios. + +Promptflow had prepared detailed guidelines on how to generate synthetic test data for your documents by leveraging the capabilities of LLM. For detailed steps, you can reference [this doc](../../../docs/how-to-guides/generate-test-data.md). + +Create a new Data asset in your workspace if your want to evaluate your copilot with the test data in azure. + +### Tips + +``` +Currently, you cannot directly control how much test data you want to generate. The amount of test data is determined by how many trunks your documents are split into, you can configure that by changing the 'document_chunk_size' and 'document_chunk_overlap' parameters in your config.yml file. Meanwhile, you can also change the temperature parameter of the LLM tool in the gen_test_data example flow and run the 'gen_test_data' script for multiple times to generate more test data. +``` + +## Step 3: Evaluate your copilot with test data +After we prepared the test data, we can use evaluation flow to evaluate the performance of our copilot againt the test data. Promptflow had prepared various of evaluation flows for different scenarios. For our RAG based copilot, we can leverage the evaluation flow in [this folder](../../../examples/flows/evaluation/eval-single-turn-metrics/). + +Clone this evaluation flow folder to your local machine or upload it to your workspace. + +**Remember to update the connections used in the flow before you start evaluation.** +![trigger-eval](trigger-eval.png) +![select-eval](select-eval.png) + +### Tips + +``` +- The evaluation flow supports calculating multiple metrics, and have detailed explanations for each metric in the readme file. Make sure you understand each of them and choose the metrics that are most relevant to your copilot. + +- The answer produced by the initial copilot flow will have a "(Source: citation)" part at the end. This is because we told the model to do that in the prompt. You can modify the default prompt to remove this part in case it affects the evaluation results as we did not append this part when generating the test data. + +- The evaluation flow will give you aggregated metrics. It's important to zoom into the metrics result for each line, especially for the line with lower score. + +The bad cases usually caused by two reasons: one is the flow is not performing well, whether because the context retrival or prompt; the other is the test data is not good enough. + +For the first case, you can try to debug or tune the flow in local or in the workspace. +For the second case, you can try to modify the test case or abandon it from your test dataset. +``` + +## Step 4: Improve your copilot flow + +After evaluation, you will find that the initial copilot flow works well and can achieve relatively good metrics. We can continue improve the copilot in various ways. + +### Improve context retrieval +The context retrieval is the most important part of RAG based approach, the quality of the retrieved context will directly affect the performance of the copilot. Take a close look at the initial copilot flow, you will find that the context retrieval is achieved by 'lookup_question_from_indexed_docs' node which is using 'Index Lookup' tool. + +![index-lookup-tool](index-lookup-tool.png) + +There are two paramters can be adjusted in the 'Index Lookup' tool: 'query_type' and 'top_k'. The initial copilot flow used 'query_type' as 'vector' and 'top_k' as 2. Try to adjust these two parameters and then run the evaluation to see which one can achieve the best metrics. + +### Tune the prompt +There are two LLM nodes in the initial copilot flow: the 'modify_query_with_history' node is used for rewriting the question with the history to make it more clear; the 'answer_the_question_with_context' node is used for generating the answer based on the question and context. + +You can tune the prompt of these two nodes by leveraging the variants feature of promptflow. For detailed introduction of variants, you can reference [this doc](../../../docs/concepts/concept-variants.md). + +### Add doc link to the answer +It's important to add the link of the document which is used as the context to generate the answer. This will help the user to understand where the answer comes from and also help the user to find more information if needed. + +The answer produced by the initial copilot flow will have a "(Source: citation)" part at the end. But the citation is not reachable link for end user, and the source:citation format is not suitable to be shown as a hyperlink. + +To append the doc link gracefully to the answer, we can slightly modify the code of the 'generate_prompt_context' node to make the citation a reachable hyperlink. And modify the prompt of the 'answer_the_question_with_context' node to make the answer include the doc link with a proper format. The final answer will look like this: + +![doc-link](doc-link.png) + +You can find the specific code changes in the source of the promptflow copilot flow in [this folder](../../../examples/flows/chat/promptflow-copilot/). + + +### Avoid abuse of the copilot +Avoid abuse is a critical topic when you want to deploy your copilot to production, due to the cost consideration of LLM model. It is recommended that you add an additional authentication layer above your copilot to prevent abuse from anonymous users. + +But what if we cannot add the authentication layer or we want to save the login effort for the users ? How do we avoid the abuse of the copilot in this case? + +A common way is to adjust the prompt used in the 'answer_the_question_with_context' node to tell the model only answer the question if the answer can be found from the retrived context. But the testing result shows that even if we do so, the model will still answer the questions which are irrelevant to the context, especially when the question is a general question like "what is the capital of China ?" or chat history becomes longer. + +A better way could be adding an extra LLM node to determine the relevance of the question to the copilot (in our case, the promptflow) and give a score to the relevance. Then we check the score, if the relevance score is lower than a threshold, we will skip the context retrieval step and directly return a message to the users to tell them that the question is not relevant to the copilot and suggest them to rephrase the question. + +You can find the specific code changes in the source of the promptflow copilot flow in [this folder](../../../examples/flows/chat/promptflow-copilot/). diff --git a/examples/tutorials/develop-promptflow-copilot/doc-link.png b/examples/tutorials/develop-promptflow-copilot/doc-link.png new file mode 100644 index 0000000000000000000000000000000000000000..8e96a0064613b4017a7f695d233a2ace9f512db9 GIT binary patch literal 129442 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 h(L%|xP5ULkDEFT!~ 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 literal 0 HcmV?d00001 diff --git a/examples/tutorials/develop-promptflow-copilot/index-lookup-tool.png b/examples/tutorials/develop-promptflow-copilot/index-lookup-tool.png new file mode 100644 index 0000000000000000000000000000000000000000..0678b66d223f450fbd8a659279155437b703c6b7 GIT binary patch literal 48270 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%0ATDTOXjBUH7 zQ^^QA=G{6fv2hyjXS!ErB+Lr>xN5trO8K7yE$s>>4Ig2*Cdp@)%Bfb%v~x}!P^mkh z^RSObaM8B9clEpevBvF$w@3DHZH2Bq#)bIAf77)2Q8kReiz*2#z|u9%eLR~rZOY@_ zNXS?5h7_Hd9pSMX&Yg6Orp zF|$ZN@_OViEx`KG&6?}nc$ax&phIE83|rev6Bj;Xf*v$TK{n!n9G^XJ!Ww6jadkCz zG~Y5JN0;RMJmA~{F@qA3z)R+Td;zvC(?RpptgqDxkjPL<{IyC4O*sqf!!h`49gDzk zrlh!`pn`1oYj}*aC)lR{_KlSI`tkF_7DT$Dr0QGG@#Ji=u8`Q;@(QH!5T?4tx>2@? zlW5po{BS^N_s*SzGl#i(+z;KCvHcnJkI}Q1<1sx!dlgl@kzK@?j&}13H-*nPuLAasaGup{u~%yV~jTh zmu4}d7pS2msC}d~4=bF2(6-lZ1-G+3qFMq-I33aqOP(Qs{*W2W#4WJ#89HcCVvpUX z{GFT_Z}u$YvUb+Vf9mBi*m9Tq3*YV@IU+_zgVI7ps02}J^xW7Uu^?4{Zw-yqm-c!n z;JhY;nTFg;Pw&Ka-@dP$(vr3A+F%r=kzw%__T$rTzo)+8Yw@~y%rU^p=buV+MzM@E zVc^hyr-Q1k@n92j5z#>n>{a z1O&@eyGPZvDi!Y<|zj@sHWarh|X>3;KQ7>0m&a|D@^XXPCs8HoaDm;3TWAsOE z?AN&Y5vvND*Gms+b$h*ffB62UA6I_Cv!iRfUP_vOb!qu*dF!zG`sox^^>RlncpddA zZ0XU<@BTdd&Gpemzj)0tnszFl*T+A6Ub;7NvEiL>gIa&RHe=K#Qq1c$x>2ErsY|#_ zc@(%Tn>Y#$-1+j{;8dQt#0`wE2O>mToR zR`d!w7|+x91yur#VTX<#KQc{m5u4ua!$F-z3euv>$U}5%fb*ELHWz1FA{^ix?X7!{ zF>aX);hO#-XMTh-$EC%Hs4aP)^FZ1%2-25@z493tO5@8&jf9}=?}&&9+mh1$11vgi z7E4SLi_Af`Y2$N!4I_6{`y)|GacBk3#(oE&b{4fhp=tikT-BDQ-slpz9%M_#qJM8L&?a0CGBUyt?v8As#9wp% zl~qiJwBj>w|0MH>^RFJDmu%Cu>wf+tG;B{C!7|m0#d8Wx9UwXy7NMvRa}V6qpZUh? zUyFjpt4z2GzAyJy_5ng*ObU1^+<6CsuffgSwWo46#7&;etF5oaZQ#p`R}9sTE_5&k ziNfDP=PT+oW%c4QO7&*j3jpDz6N;Pb{vOa}2EQf@5o|;NtP}gRsc*m3*9JI?*gC-rw<6^?2}y9I>_s9jX@1Z ze@OKmHr)HMkDZI=q75ngR$Cm|G(zP!V1o~dk6$gc+;_NHvYm~u+OzVNgTnqE=W#FM z{L$wZe=oJsUc6?(?*sBr-ip86$$l!pfy2I_zz*r@JFnF4N*x>1<({-j9yZ(PUO~m$p>KcpIO}YA*)#50=I$Pw*s1vTLZ8`_ z%Oe8_eA7184oLqT_@d*t4}FxzYPfIgRaldx$vYxU%b0 zzWFRw%qQYV{3edj<-(REl6?;%6_}XAAd$==aYYV$c!rZpKOJfK7V?qP+p@kWT^3$PYkgKXCLiV9-@mEHn#rnS1E=Iuu{!@BfT70+J_GH`Bi(9)M z7O$nc+HYXlfZv|5fnu7;1gE&`;tDf-p3Y-_iDy6c7YQdH=ZN(SHaxyF zb-kJXl{*BgLu(t88RUd+;qIL~4V|6q)cqeptTB1fjDNF)%M|A&?h>E63-4|gIAkXS zH(W#@$LV8x%ESh+SjXchIEFx1Gpk$2J9ec8cj zCciCOYc>iSHhDboC8wmk0|nyV@I=r%mLeWO7IKu^FB6f=5>F*?ROF}^Li0BAPC4VR z|L=$4p`S;49f4E}KyrW%%6wLrFNG1KFIQao7x_ZemEDiVcFjJp?0VYWld~&JyRF^Y z#=m-X-jeN+fH2MW4$&}5ijUj1#v(A`+~BL~#a_od8J{sT(@3p#%q>i}vO3qYoxg!< zho{;55fwB&r&m^OKOnlv>TL%UZGLzBaJ_ND*cJ^+H+A~M{K&r{CoZaoOxt*)mE97h z((!M#JQX*#E^Syd%i!yl0bNv8RoEu~Ws_xHpI$rKIR8zJh=?O5PIF(h!-C@HO?pl- zq^A0Z4pp;ckz4Sv-Q(CXLaqAk+TXo)eD-9_JSAti*6i=cXt#5_81qCBkWuSiH$>B9 z;qpfZntwF{PrpCt(F4Jz>l=HxuLd>4{;=%w5)pE zGbq(c6!D0c#2WdxgZfQA_MOq@$4~EezPRU^VY{D4xaXa3<-mz`z!fseNJV(=LJYzw z8R-J8M~XMO-|B%oK5s&})Owqn-5--`=4wd|ws~#c8`~0|fx$mYvhS~V>(EjGrhZn? zzdl?W=kIE>|NQmW)6?fWiuM2Y!{@{niu0-$XdvUtmri|bAjVFr?&P|=T&eC=YvZM; z#*v%pLSLGhOnT^bt+oE^J$6qA7Ms(7#)U1&9n_aL5gg~xGln%W+!k{v8=I2cZf8Gx z$|ecY|K#s19bO5Ka=W?y_Xj)Z_A$4c%jV6jM1CMv;D{FEuLmTp5L}cD&NEmrWM9d@ zh3iMlN(&wsYC*@Zg#qVMi{doTJI7GC2{0rR7&xm#XY4FHg*F%5Gapn=mOF4P#@;(D z;(&vHYx_?El+zFFR;5e5>w6@2&96H)#iZ>N=Sk3?>UQ}vRb0%;LcFLJ<(}Jc#+2)f zJ#%l+K@bGFE0z*u)t$bs=OWY|oz{n2Hg+qa3sh>c zrDf%{zyI9PrnMPp1OIk#ONU=?eP{fhhDqLHyt|YrrT~2H3O9d@-f4WkUQ@a8HPt4j zrZ_AQoVXs+svi`Fj?Tk4%@)57#p~`O>mr-d%AO`D>vp6IVnrkO(F?zI(?n(c9u{PmNN zD$rOU)RvtRRGod}eDwoSE-z(HO$ZvReehDZ5)(^9<2Hs>+1c94KpTi|b0BNQw<4rR zMc8*WE%pZ9mx(k*@hT)-%geNC)ti|k1R<_4S~DGYd#9 zvh{$kb+{gc?`UX{|H}#Zs4^b zkeJ5z3(ukPfv}NP5vX0@-Cy~3nPV?=1I*U8G*{E~2|!0jP<*V)-Ep?Z`452$?hiIEd2CdJ=`V$$6-b`Y&FS|(fS1?hvR ze+yYq2L!*6W8L2@%8gr^1Yqb;RWb|U=NzCXS3}gR$cl`c=Ks!c!j>u<1r+y_KvA~2 z?mIx4#UnS37_1kZ%K4Mn#xa+TqAxfnOdXwjG~L01cu>f=tyGo_C(&W9g)SAZL>yo4 zQJxlLTph$gTngtc^J-K+A8`hGm79CpxvtuR8O(i$5B~;Rrr54?$z{H)wD$}g(P^Qx zbfd&vylT}Wc`ca@qSGR;2hi<|t$r77`E?#cn50x-qINXGa@b^Ufv1ik{LV5T!Qjfl zca9PV4V8ZX{j8($f9|5hS1-R4)$Q)E>qhpiP!0F3S4xalhdH77U3h3)OIEBuMArGY zQLsNe2{mG8rdVmfL>edtmdUbQx-_!1y093G8W2L!1#MV3>M1~E8I^#NY0+V@3;M7n z%uWEKB5Bq(lKLHO(6#93+=7C6uOekh+Ka1ex)WlgwOsD)^n0&fy=Zv7Q1~&g+8!K1 zlwv^4jJN90;ful1Yj|*N3nITkyc;l{c-e|<=%Ea~vLxBI_S?5_(xsqn0oR~cHGDO% z`yCPxWnoLCH_V5%rBOu@CV5y_|5D6)O=C)0uwnNHN~-SK_6Z3I?@uYU0L_$T3{da) zDBwA^L+#6!A`)R^vpih6xXZ@Dqr-)BKBn@;ytYz9Cr}g3mL_6C4G>BTx21ld8~Ka8 z|NNCSemzemT2c`(kSpQPZQ!O28yYRd{agkog@Mw}V8+ohrj#$>{=lF$J3t|{c!r4; zC6PJRh1SeQplM)NO#%=IPE1=aY>(YbDzo%vdI^X!<)sssh6~r+?feFj)yd8abc?Jm z$p>&!Y}ZCxCvwZ?%`)ogKQj_V+~||22RF*lBv!RExIhJ%f}x~R=rLfx`@>z9^g|~F zQzE11I4_)~*nwc)A=J`p8v9Q-t0UQZ#=katiQ%k_M_Z2DRNq(1 z!nOU??~irvute$CwfGsuPpitwjAyu%wq1thWl7|-FpD|hVT2lAIAEE_g8lMeunBez zok^lub?}OW#Ogw|;lqDdpzvfOBzV1};bAW?EsR1GfPrphXV;!uqQh#80Iwyx&RtyfOSo+DR|Gafwh_Oyz5?wjk?@ICL{Zj84Il;X#WEeScfaD;<;#}YRu&ne5NVN)@^<{?A>XT#|5X-JulD}h z?lIUZK$EJ|0qBY zVBKLbR~RHl{YeyghYxOIpbE9^UTRk$eJMGSsq~>cB0i5V`}W_3@kixDJ-*f{3>`X@ z`YE7>2e73J4whxt( z&r#CgtJYXsdoLcHPnknr2XMmyW;#SZRtQ#)w`;;8Xt~$Fe1~|?#>pj#;hx2R9#js9hS!JXGxQS`~ zsllnqsG_z)zEF`ylYOHn`y65C%bDTsfmVqnI`3IF`3mK)UNAykRUJ7Oih``_bz+f%BYtCg~7_5a&gD zYb=Xwc2>uF-vECsAi?Uo#$+>AM$DhilgT+0J6!0fIV;yJUVQp|3_dg~#k+ykM-+_Y z`Lp_g1Yp@k&T^34q61hsEmSQybrJR8eHCdqmf(SAcRO%Ihg#MHrNDh&&NTHyZ0fzWGKVQ-9 z{G3=y5BetNL7U-kpgXRv%~DU{I3X5ruaQG1^N51n$E2 zpC$^hC(K#SLJQ4sjZkuQg;1>&X{Rx}$2;Yse#h5UPd!1$Maf*hP_T3&t?aTxqlmmM za^w4B$=S>>^P4`(FEPTOL!K0~47Dy6AS_};M-oP+AcHhK7tBlkOIj1VI{X~m=6|}* z`4T%2rhLgU)bvL6i~Vt&3p$ZTfD$PtjH(wVfb@5_($cQp8j`(rV0C42z^ZW2Ffr34 zxeBhse^(8^7X=*4*bbXn8iW`DFD*&>dH|JKK>etcTWN^wADO3?o+x%6b& z4bzZmAx7n}p5-)rYV~T%WLjLl6dzhaC9l-U(ec9N%h%s_FjQ4S!Jtaf{c8V+Y#-ib zg4VJvK=DThFRCxxpJ5J2)4yWt&q!25ar0lvoxk4kR^BaO_W$pGSk*6Sg~UuA;>l-{YF1aD zqy=FCSQiTBH5mc_{f%BbA8(kna~nYJVD_bMcd?&1u^s`vV0~2F*wO!W{Q$5o@9SQr zaA&*@CNQW!S3WtR!{Qo!33W;>cdzOC<+*TpMIc=UN#X1 zaB2?(jyj$X{1-Otzd{(&wk7iyC^O_|6cgDNbDad5wy?XZ`S4qzlp zY*EK`b%?1g9dG~NH@(R=p4AR~XkR|_g4nGmWsVScI4a3|hk8yPX&Dc7bFI2hSl&hixWUJ`mztRh^U%&jQ( zWhD(4c?f4j0nx$(WMR;JShnk|oFBW@iH3d;MJ0XAlqplh{{^ADKq}}YbkoWIhk$Vo z9X)!k%l7|1f0JrXl6vaiW!cX&Os$RknE2b2dX1*s+%~agtJC)DCj7QeJKFTXs9}pN z3oC=Nx~K-kr=;|L8sG0}sPXDc$;zt-574li&}iMHMwaR`8#Qj&sC~o7rLAApC@bpe zxn+mF{TR6(w|3{m#cvBwC7N3s%H$avvCktwdsA4ra%)yb#(ZQ6$*^$EFQYki|99ab zWriMgXl}K&v}BY+4lQO6^8KIS;S|JJ2c}Y2Csfnk9CJRfckfe>omA2hqVq!F zn6wxie6s@hF=&!t3U60GtgwqA7;QIh^nh96gX+BN)vuoxV;RkwG;Y3Ne~U19q-p%3rBjQrE6sZryC2(p^D8_j=9C>*vP*xXsY6|1^B* zF?IU%byaZr^Ue4r9^HLtIMl|B znZI}PW2A zKC(-6%bvXA-D|@q9Mn7+deM4zzq0j4_MVLtZffRgAJ94+5Z>N?v`O(nzm?B=ZFp0- zSWPRxW8u#)+j&w&>|t{JMdv{ZZj)+r+|d%pKYsj-B+%qZJ%wvi`R!pF6Z(a04n3vp z<+*u;*UTM1e)nbQq}{C)Zfbuja2C66C+@@}|`Dah;D@%y(9v#WNNE;K2~*{QBQtA#+xfq@y)sW^tUm`(XqVJ?y z&o7RFtraG`$hG_Z#|QfUA9(H9=Wic6DJaBeM|fX!eD?j*{=8pPU+(2U*mNJa{QFzn z%-Yw67ghSEGS1>%1BJEKA6_*7{!%4I^49A16URUZ&oT0wuQx zOOrvQDzFBQPfVOcJn$ry5EH@keMQCwKA2~k1L0Ny1*Yvvf1t`UXm-QV1a#h=u`Y(4 z=h{@hDsgAXUh_Y%?viou()H#OUQ~nNX{>uarBUO?SfkG(J(Yd@cv#ur&u;}~2K&Z$ z(tD;dOZw# z!sA1RyTyX#3^2cb?f#O?Ucc_2!nKnGnBK_&Qv0Fr ztvZ&>hp_6*Hbg$#wfQk0Ed7jj_32lvZR1t3+%VF$TY0em!BbWSy}$kV@CHlY{bRmO zM4F~hHo$@NR=LO_ds*`7mgiy9n5xT{Lf^QVc$*m8UUn#5$?Glks%-lGgX!x1cG|cN z22o!r5DBGcoxc@Zj8O7nsAL74Pf=F%Rjf&Sk@4v6&oQ}cib<`lZ8PV8MgX;UY@sN( zW864%94cM8*PIuw)-dN+4jMUm*34Y-`}o)$Y5120n4O4{t5U)4&0(Bkq+OTz%$RY#37k@E@a z#cx)iM?IS1HM95X=NBeQbG)4;+fIqcN6g{CjTlzzU-)pT`bsb{^$snLjd$L9_#4nr zF}{2(K(DL-qS1-^8l8n*h8QzKi}9TxhR)Hir(amKeP-{c8;YY}Ty*n8;lg(#L~M zI*C3Nk5+}Wn4@}o+>e{5+S|h}tOqLrl-jjBgOcPSTLyL|Qn^2)Qi;HfDK*q=K4>RV z{3%#OAYJJHVp6y~i71QcZ2eIO z$TnK)okOv)vC0oX&!aTJ`3zuOT#+D|}yR`HlDqJh` zt+i}+a1B+w&Fk=Zl^Z~ra!z!p7@tDApzZCubH|PqFpw;{iY?Kw@e9LLBltQ{MFTDa3r#)lF6Y!6-P&*0U<8x{j-hMAW)KVn! z%ojbscm`xcsbj}LB$^ZX`BV_H6kPjWJbzxmW)OV{pRlvfywo~idF4lRM@8T#DcmwktUk2lIV8XZf$zu)HCAK#)_nUW z=a+v8SrDnuJl0d$A8MA%M;r#olW=0xTwqbx(8ps>Q97@F@m3QlevWfp3{Zcizy;iQk?{wQD$K$_@F$*spqIGe&wQ%7z7;6u?}AqQ*o8iKd!#l<^$^=zVH z{Uyt+t%IpzIpniszzmi6KWW#JZg7C;97f!|cTZA5qpzd4d^(ROODL29Q{uDp)7T($ z7N+v|CPa2}8BMeP%$fU;hi;m?#Gn(uqc&`p;`WL3{O+Efp78c=$BsGZq+R=?WXVe# zmNMGVQE5**qX!Z+;OPx!(<|s}ta!8tq6S`{oHVgqIGnU11=ipUokMn#b?&EriCccu z7790Wnh#Ax8@E2G}o=?tW#r6K;NcbL9y?J^uYJ_->udHqxI`Ace8)<8)$9& z(Iu~5i7mF*?LyaOn{#Gb5O2t?Nql4X6DL;HIuSl6WAWzzrPyr$TpU0rO`aTqXtV3s z&ALbtl0kCY6TUzUvkIPMULaPk&WbXGmYutFsUO^WB|KXZAv_4jtpQcegEHf8<~$%? zu)6S1_F~+B@xp{}G^o^d?ZMnrKU4qOfWhrz{#v_s?IA3783d!H+A#Soizc=7|Jf3l zk&zKhbEC~fudR{y-n}}9-{vJ2#H4z;u%07sgZ1^Uz@`$^CWX-g79a;Uy|7SL6ew^1 zSNG*X$_=P0iy-UFnHIO>bwg#Mmi}`&;_fDOHga{ctSQjAq z322M~msFG87gouB4`v;hUFgKmTcuwP#3SIev_6=bz;f*3KyREI+^2n>`L%=FVg)s2 zy|8>}E4n{>&$;=~bC;O~(`55CA}=$0PrJlx?(2dJs@m&%C|(Xdv+-W1JTo!~e{O2- z^(s(;oIMWPgc)rUO0k*5pAnhU3B6$%XQhZ(R+O#9-=fc?J!~DZmmNK6e=a}xmanQ- zIWBiZGJv#uHw+k^m`_c=yz&T6&*w0okvoOJsnM;S)L{&0tkc%kPNsiWYTtgTd8_dn z8it9QRVQHc^@2LBxkq#yhUCyN%-jqrM0Suos(KQ!#oN<;%d2sUwXJ}beL&D}Tz`0N zHQ>L5Px+{HIeBJ}HFJ&bg`CcrJHf={!}?w=SC~zAeKXj0?kM9Qfn)8OKc|HC5O6`d zN6ieM2AM{SY zoN|^gz&KwJJAx<0vEn5};{TIk@`CNUb$VRR!__8n_wK2xsut}kM(Jxn39}ww-1(>O zI)ytC)7Ui|k^JxW#-bwtQi)$NEC@KGQF_-=wo~x+m^#pKE71fcmwS=Jh%p{tT90eL z;Tu2UL`~)J(%{_w+d0#wc5c)^i=Is$0mMTdTcgdYslvw^U zm(y-JtW(71kBha?-MgWUI7c7ATOX@l5WZ~x%-(aoQk;0#{oOQ8QFePKt#G5Wph{g) zJI0byfNH~?h>i20^|&>l2KiNGL<=j*PAmLI_z)?8^Q&K6@_!P+1H*mj-j7F-=t_{{ z$vN1*OPBs+AW9j({ET`~;;?3A%3NtX_yRwR zDfg(YT9lPHA`hU-APB6?&$$gUv$D2&tg`ZygPNa?elZmX8bYb@ITjK3r*L?FJxF`& zcrubkj$K;ktHt{#ud8xfUpX;~`p$%^s|*;9t3-V!?$oHnv|Qb=T0$q{ReGjoOX%gQ zR%@?*Slizr^<=$};sW=QmdaWgrxS~_yqo@PHEn+H>Cosk9evI0G1FFTcqDp&W?0Kj`0d%VR9SY&A$ zGR{?6?i9YnD>mXLHKn_k*UGKLYv(kYuRYg2uw91-bZ11j=uqAF$QvIYpUkTU!d@59 z83v(hfWdCh$Qjc*v*486z%4<+`%qhe%@qHH>WKj65_GuAbR>#yW_wWV$L0l}CFaKkt z#Jg|RIdw){W1fDjzeLDhIwP8Sx zF-YjsW42snC|ntLIK~Nc%A8jP^w8&zMk!-O`gEaRO6-vvFFAknL zR(vz%=A?;VU7l^Y{IYNwEl7dpTaWh}NBs!9&LjH2HQ&abI(Z99Y7bVjoaRtiNG?La zwJKX@3`j3!tF(N&w$cS$-1D?U?38bZGIOBZdZks0{iA`d&K`&$Dv_Gw*rJfCgY!8t8 zg7DBAh^E(>q`q3F1a^2#Keq5Ck8PL6p<~1WdhHP2LH!Dgw(H3VCuJg?U2n9p0`f?+ zl;>`|o@1>OHTuXFF6URiX9av$5N%xkfHpQM9IXnR%!+7D7)A&eMwXCppOi$B0sii5 zI35_d=tX!yEsxp*j{bPO$K_dKeGOc|Y)ZMq$|2@4rU2_lCk&%_JwAUIeJ}dsD0doZ&QkRV7Z7{h*;BaG- zjEIW40`zo_$|fF?T_TW< zNZUg{m5S}HFY>4u2Hm8cmyCiWY!)IoSaE)NE+sl=x4+g`K($BCZ^fZG$Rzyi%-%<& zDFi_&jIH|?M(ya7wGQXF0qeT#IX0vwK)Z)a9Dfv%rC$ zlZ(gnb7V^O`J7gg$Ke5`tM(5Fu;w=;Mo=J}gRY==3%OqoeHe_d>P+EVI3xnY3C!@s zXQD70k6L%g>(Yq!bn{BDw|)87{t%f=*~j&ZcIK( z_&41m1A#*H&1+Jof}Nzu@mEs|){lLAyrT{slUyi#t;CG8k{-WruU?aZRno{3drwBN zuV;lo6A;GId9nb^2Y|$LUQW!~?hU?3flsW!-lve&$wM0#xK^<6NS))xhrX2p}qu72o3^us3Txru(z(o)M+ zx*Ce$#9Xke2sp}=`6|dZt>4@~od4w8w#MCX$Mse&B)+J7&5YXo@wD6w@_}3im{mV! z)xbAXV4GVq#gwu^CccSudbDrN$F5Cbu(kX-daH+HujKjj>Ydm^^P*I0W0Do@{SD?%cHfp}W>0Gj-qw@rhOVCY2>w^I0v& zDLTQryMbEye|KZDO9Lb%6-qrhwfYrEn;w#AiCPrPo`oadjKMXAGBKFX4uM@r^ce1q zE1?gvnAyBmzR6d`?Y=kP9-ulS@NAqMQ7

?Fmio88`YDS{)kav!Uy^kwKBl^?yL_ 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 A6#xJL literal 0 HcmV?d00001 diff --git a/examples/tutorials/develop-promptflow-copilot/trigger-eval.png b/examples/tutorials/develop-promptflow-copilot/trigger-eval.png new file mode 100644 index 0000000000000000000000000000000000000000..6d26f25e611aae9f1cd75b1ff79bcc9d6af439f5 GIT binary patch literal 36821 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 literal 0 HcmV?d00001 From b17394b2782b7d1417ce1079af80e64b76ddad3a Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 8 Apr 2024 14:39:02 +0800 Subject: [PATCH 090/112] add promptflow copilot sample flow --- .../answer_question_prompt.jinja2 | 17 +++ .../answer_the_question_with_context.jinja2 | 1 + .../check_query_relevance.jinja2 | 38 ++++++ .../check_relevance_score.py | 6 + .../chat/promptflow-copilot/flow.dag.yaml | 129 ++++++++++++++++++ .../generate_prompt_context.py | 41 ++++++ .../modify_query_with_history.jinja2 | 17 +++ .../refuse_to_answer.jinja2 | 4 + .../chat/promptflow-copilot/requirements.txt | 1 + .../chat/promptflow-copilot/select_prompt.py | 8 ++ .../develop-promptflow-copilot/chat-ui.png | Bin 0 -> 250504 bytes .../develop-promptflow-copilot.md | 34 ++++- .../mir-options.png | Bin 0 -> 9912 bytes 13 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 examples/flows/chat/promptflow-copilot/answer_question_prompt.jinja2 create mode 100644 examples/flows/chat/promptflow-copilot/answer_the_question_with_context.jinja2 create mode 100644 examples/flows/chat/promptflow-copilot/check_query_relevance.jinja2 create mode 100644 examples/flows/chat/promptflow-copilot/check_relevance_score.py create mode 100644 examples/flows/chat/promptflow-copilot/flow.dag.yaml create mode 100644 examples/flows/chat/promptflow-copilot/generate_prompt_context.py create mode 100644 examples/flows/chat/promptflow-copilot/modify_query_with_history.jinja2 create mode 100644 examples/flows/chat/promptflow-copilot/refuse_to_answer.jinja2 create mode 100644 examples/flows/chat/promptflow-copilot/requirements.txt create mode 100644 examples/flows/chat/promptflow-copilot/select_prompt.py create mode 100644 examples/tutorials/develop-promptflow-copilot/chat-ui.png create mode 100644 examples/tutorials/develop-promptflow-copilot/mir-options.png diff --git a/examples/flows/chat/promptflow-copilot/answer_question_prompt.jinja2 b/examples/flows/chat/promptflow-copilot/answer_question_prompt.jinja2 new file mode 100644 index 00000000000..07a75f1ae8e --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/answer_question_prompt.jinja2 @@ -0,0 +1,17 @@ +#system: +You are an AI assistant that designed to extract answer for user's questions from given context and conversation history. +Politely refuse to answer the question if the answer cannot be formed strictly using the provided context and conversation history. +Your answer should be as precise as possible, and should only come from the context. Add citation after each sentence when possible in a form "{Your answer}. [Reference](citation)". + +{{contexts}} + +chat history: +{% for item in chat_history %} +#user: +{{ item.inputs.question }} +#assistant: +{{ item.outputs.output }} +{% endfor %} + +#user: +{{question}} \ No newline at end of file diff --git a/examples/flows/chat/promptflow-copilot/answer_the_question_with_context.jinja2 b/examples/flows/chat/promptflow-copilot/answer_the_question_with_context.jinja2 new file mode 100644 index 00000000000..4412d002b90 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/answer_the_question_with_context.jinja2 @@ -0,0 +1 @@ +{{prompt_text}} \ No newline at end of file diff --git a/examples/flows/chat/promptflow-copilot/check_query_relevance.jinja2 b/examples/flows/chat/promptflow-copilot/check_query_relevance.jinja2 new file mode 100644 index 00000000000..922cefaca3c --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/check_query_relevance.jinja2 @@ -0,0 +1,38 @@ +# system: +You are a helpful assistant that knows well about a product named promptflow. Here is instruction of the product: + +[Instruction] +Prompt flow is a suite of development tools designed to streamline the end-to-end development cycle of LLM-based AI applications, from ideation, prototyping, testing, evaluation to production deployment and monitoring. It makes prompt engineering much easier and enables you to build LLM apps with production quality. + +With prompt flow, you will be able to: + +Create and iteratively develop flow +Create executable flows that link LLMs, prompts, Python code and other tools together. +Debug and iterate your flows, especially the interaction with LLMs with ease. +Evaluate flow quality and performance +Evaluate your flow's quality and performance with larger datasets. +Integrate the testing and evaluation into your CI/CD system to ensure quality of your flow. +Streamlined development cycle for production +Deploy your flow to the serving platform you choose or integrate into your app's code base easily. +(Optional but highly recommended) Collaborate with your team by leveraging the cloud version of Prompt flow in Azure AI. + +Promptflow team provides some builtin tools including: LLM, Prompt, Python, Embedding, Azure OpenAI GPT-4 Turbo with vision, OpenAI GPT-4V, Index Lookup, OpenModel LLM, Serp API and Azure Content Safety. + +You can define your flow GAG file using YAML file format following the pre-defined schema. +Promptflow also provide vscode extension and visual studio extension to help developers develop in their local environment. +You can also upload your flow to azure cloud using cli by installing our python sdk. +Promptflow also support image inputs for flow and tools. +You can build or compile your flow as an application or deploy your flow as managed online endpoint, app service or build it as a docker image. + +The key concepts in promptflow includes: +flow, connection, tool, variant, variants, node, nodes, input, inputs, output, outputs, prompt, run, evaluation flow, conditional flow, activate config, deploy flow and develop flow in azure cloud. +Also include open source, stream, streaming, function calling, response format, model, tracing, vision, bulk test, docstring, docker image, json, jsonl and python package. + +[End Instruction] + +Your job is to determin whether user's question is related to the product or the key concepts or information about yourself. +You do not need to give the answer to the question. Simple return a number between 0 and 10 to represent the correlation between the question and the product. +return 0 if it is totally not related. return 10 if it is highly related. +Do not return anything else except the number. +# user: +{{question}} \ No newline at end of file diff --git a/examples/flows/chat/promptflow-copilot/check_relevance_score.py b/examples/flows/chat/promptflow-copilot/check_relevance_score.py new file mode 100644 index 00000000000..27cfebbec96 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/check_relevance_score.py @@ -0,0 +1,6 @@ + +from promptflow import tool + +@tool +def my_python_tool(score: str) -> str: + return score == "0" diff --git a/examples/flows/chat/promptflow-copilot/flow.dag.yaml b/examples/flows/chat/promptflow-copilot/flow.dag.yaml new file mode 100644 index 00000000000..e10ca0581c9 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/flow.dag.yaml @@ -0,0 +1,129 @@ +inputs: + question: + type: string + is_chat_input: true + chat_history: + type: list + is_chat_input: false + is_chat_history: true +outputs: + output: + type: string + reference: ${answer_the_question_with_context.output} + evaluation_only: false + is_chat_output: true +nodes: +- name: modify_query_with_history + type: llm + source: + type: code + path: modify_query_with_history.jinja2 + inputs: + deployment_name: gpt-4 + temperature: 1 + top_p: 1 + max_tokens: 1000 + presence_penalty: 0 + frequency_penalty: 0 + chat_history: ${inputs.chat_history} + question: ${flow.question} + provider: AzureOpenAI + api: chat + module: promptflow.tools.aoai + use_variants: false +- name: lookup_question_from_indexed_docs + type: python + source: + type: package + tool: promptflow_vectordb.tool.common_index_lookup.search + inputs: + queries: ${modify_query_with_history.output} + query_type: Hybrid (vector + keyword) + top_k: 4 + activate: + when: ${check_relevance_score.output} + is: false + use_variants: false +- name: generate_prompt_context + type: python + source: + type: code + path: generate_prompt_context.py + inputs: + search_result: ${lookup_question_from_indexed_docs.output} + aggregation: false + use_variants: false +- name: answer_question_prompt + type: prompt + source: + type: code + path: answer_question_prompt.jinja2 + inputs: + chat_history: ${flow.chat_history} + contexts: ${generate_prompt_context.output} + question: ${flow.question} + aggregation: false + use_variants: false +- name: answer_the_question_with_context + type: llm + source: + type: code + path: answer_the_question_with_context.jinja2 + inputs: + deployment_name: gpt-4 + temperature: 0 + top_p: 1 + max_tokens: 1000 + presence_penalty: 0 + frequency_penalty: 0 + prompt_text: ${select_prompt.output} + provider: AzureOpenAI + api: chat + module: promptflow.tools.aoai + aggregation: false + use_variants: false +- name: check_query_relevance + type: llm + source: + type: code + path: check_query_relevance.jinja2 + inputs: + deployment_name: gpt-35-turbo + temperature: 1 + top_p: 1 + max_tokens: 1 + presence_penalty: 0 + frequency_penalty: 0 + question: ${modify_query_with_history.output} + provider: AzureOpenAI + api: chat + module: promptflow.tools.aoai + use_variants: false +- name: check_relevance_score + type: python + source: + type: code + path: check_relevance_score.py + inputs: + score: ${check_query_relevance.output} + use_variants: false +- name: refuse_to_answer + type: prompt + source: + type: code + path: refuse_to_answer.jinja2 + inputs: {} + use_variants: false +- name: select_prompt + type: python + source: + type: code + path: select_prompt.py + inputs: + answer_question_prompt: ${answer_question_prompt.output} + not_relevant: ${check_relevance_score.output} + refuse_prompt: ${refuse_to_answer.output} + use_variants: false +node_variants: {} +environment: + python_requirements_txt: requirements.txt diff --git a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py new file mode 100644 index 00000000000..90345610e22 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py @@ -0,0 +1,41 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +"""File for context getting tool.""" +from typing import List +from promptflow import tool +from promptflow_vectordb.core.contracts import SearchResultEntity +import re + +@tool +def generate_prompt_context(search_result: List[dict]) -> str: + """Generate the context for the prompt.""" + def format_doc(doc: dict): + """Format Doc.""" + return f"Content: {doc['Content']}\nSource: {doc['Source']}" + + SOURCE_KEY = "source" + URL_KEY = "url" + + pattern = r".+/community/" + replacement_text = "https://github.com/microsoft/promptflow/blob/main/docs/" + + retrieved_docs = [] + for item in search_result: + + entity = SearchResultEntity.from_dict(item) + content = entity.text or "" + + source = "" + if entity.metadata is not None: + if SOURCE_KEY in entity.metadata: + if URL_KEY in entity.metadata[SOURCE_KEY]: + source = entity.metadata[SOURCE_KEY][URL_KEY] or "" + + # source = source.replace("azureml://locations/eastus2euap/workspaces/c3a40c81-f452-449b-b62e-ba25cf5b6029/data/vector-index-input-1705993805833/versions/1/community", "https://github.com/microsoft/promptflow/blob/main/docs") + source = re.sub(pattern, replacement_text, source) + retrieved_docs.append({ + "Content": content, + "Source": source + }) + doc_string = "\n\n".join([format_doc(doc) for doc in retrieved_docs]) + return doc_string diff --git a/examples/flows/chat/promptflow-copilot/modify_query_with_history.jinja2 b/examples/flows/chat/promptflow-copilot/modify_query_with_history.jinja2 new file mode 100644 index 00000000000..2134ed187aa --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/modify_query_with_history.jinja2 @@ -0,0 +1,17 @@ +# system: +Given the following conversation history and the users next question,rephrase the question to be a stand alone question. +If the conversation is irrelevant or empty, just restate the original question. +Do not add more details than necessary to the question. +conversation: + + chat history: +{% for item in chat_history %} +# user: +{{ item.inputs.question }} +# assistant: +{{ item.outputs.output }} +{% endfor %} + +# user: +Follow up Input: {{question}} +Standalone Question: \ No newline at end of file diff --git a/examples/flows/chat/promptflow-copilot/refuse_to_answer.jinja2 b/examples/flows/chat/promptflow-copilot/refuse_to_answer.jinja2 new file mode 100644 index 00000000000..33d0a5b04a5 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/refuse_to_answer.jinja2 @@ -0,0 +1,4 @@ +# system: +Repeat below sentence exactly without any other words. + +[sentence to repeat]: Unfortunately, I'm unable to address this question since it appears to be unrelated to prompt flow. Could you please either propose a different question or rephrase your inquiry to align more closely with prompt flow? \ No newline at end of file diff --git a/examples/flows/chat/promptflow-copilot/requirements.txt b/examples/flows/chat/promptflow-copilot/requirements.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/requirements.txt @@ -0,0 +1 @@ + diff --git a/examples/flows/chat/promptflow-copilot/select_prompt.py b/examples/flows/chat/promptflow-copilot/select_prompt.py new file mode 100644 index 00000000000..c88326c7230 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/select_prompt.py @@ -0,0 +1,8 @@ +from promptflow import tool + +@tool +def my_python_tool(answer_question_prompt: str, refuse_prompt: str, not_relevant: bool) -> str: + if not_relevant: + return refuse_prompt + + return answer_question_prompt \ No newline at end of file diff --git a/examples/tutorials/develop-promptflow-copilot/chat-ui.png b/examples/tutorials/develop-promptflow-copilot/chat-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..ed5a5a2714c9d40ca228d746a763c190d2260918 GIT binary patch literal 250504 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

lIK-|Mq841c#$7j&`w70-z1+Ap?Iu2YK{ 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

8csze8fD5h|=$*CQ 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∨ITqx3y<_1Cred9-qqik|qv&dy_bdH9Azky+Ps zm^O~d4-;W8ba2!Kg@m+J)iZujVfqXT4KoSdrI{JTY9FHdhQG&j)t=GQ`An;>and=} zCXDn&6)^?P=VCiD-J7_OFO6L(1jvRBVuFOGN-R?gpr3$f+#(pCu~oN++Xa(|^0 z&As>a5&|v#!;|*_xvBU;+T(eH;wBIenetuX&vTd4D|>&YIEA93PXltcl^2!j#m+Aw z@~_Tyr$o%4OyRpyTKSJ;E+gv61N~cZE+G(xf7#7L-T(L33%r+v%1Vx@p31<05c1MW KQh7+jxBmsTpim$H literal 0 HcmV?d00001 From b55043a3865623b94a7a420de2d0d5dd5272140c Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 8 Apr 2024 15:40:10 +0800 Subject: [PATCH 091/112] refine words --- .../develop-promptflow-copilot.md | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md index 3ba613ea6c6..64ecfae05ec 100644 --- a/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md +++ b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md @@ -1,13 +1,14 @@ # Develop promptflow copilot -In this tutorial, we will show you how to develop a RAG based copilot step by step using the toolsets provided by Azure Machine Learning promptflow. Specifically, we will cover the following topics: -- How to initialize a RAG based copilot flow from AzureML workspace portal -- How to generate synthetic test data for the copilot -- How to evaluate your copilot with test data -- How to improve your copilot flow -- How to bring your copilot to customers +In this tutorial, we will provide a detailed walkthrough on creating a RAG-based copilot using the Azure Machine Learning promptflow toolkit. Our tutorial will cover a range of essential topics, including: -We will develop copilot for promptflow as example in this tutorial, you can develop your own copilot following the similar steps. +- Initiating a RAG-based copilot flow through the AzureML Workspace Portal. +- Generating synthetic test data for the copilot. +- Evaluating the copilot's performance using test data. +- Enhancing the functionality and efficiency of your copilot flow. +- Deploying your copilot for customer use. + +While we will focus on constructing a copilot for promptflow as a case study, the methodologies and steps outlined can be adapted to develop your customized copilot solutions. ## Prerequisites @@ -18,9 +19,9 @@ We will develop copilot for promptflow as example in this tutorial, you can deve ## Step 1: Initialize a RAG based copilot flow -Firstly, clone the promptflow repository to your local machine. Then, in your Azure Machine Learning workspace, create vector index using the document files inside `./docs` folder. For detailed instructions about create vector index, you can reference the document [here](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-create-vector-index?view=azureml-api-2#create-a-vector-index-by-using-machine-learning-studio). +First, begin by cloning the promptFlow repository to your local machine. Subsequently, within your Azure Machine Learning workspace, proceed to create a vector index utilizing the document files located in the `./docs` folder. For comprehensive guidance on creating a vector index, kindly consult the documentation available at [here](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-create-vector-index?view=azureml-api-2#create-a-vector-index-by-using-machine-learning-studio). -After the vector index created, an example prompt flow will be automatically generated in the workspace. You can find the example prompt flow's link in the vector index's detail page. The example flow is a typical RAG based copilot flow, it will be a good start point for use to develop our copilot. +Upon successful creation of the vector index, an example flow will be automatically generated within your workspace. This example flow, which is a standard Retrieval-Augmented Generation (RAG) based copilot flow, serves as an excellent starting point for developing your own copilot. You can locate the link to this example flow on the vector index's detail page. This is how the example flow looks like: @@ -33,16 +34,16 @@ With some minor configuration, you can open the chat panel and directly chat wit ### Tips ``` -Prepare your data carefully. The quality of the data will directly affect the performance of the copilot. Promptflow had prepared rich and insightful document in the `./docs` folder, so we vectorized it as the context for our copilot. Meanwhile, we filter out the image files which cannot be vectorized and some markdown files that contains no meaningful information. +Currently, the volume of test data generated cannot be directly manipulated by the user. Instead, it is contingent upon the number of segments your documents are divided into. This segmentation can be adjusted by modifying the 'document_chunk_size' and 'document_chunk_overlap' parameters in your config.yml file. Additionally, you have the option to alter the 'temperature' parameter of the LLM tool within the 'gen_test_data' example flow. By executing the 'gen_test_data' script multiple times, you can indirectly increase the quantity of test data produced. ``` ## Step 2: Generate synthetic test data -To ensure the quality of the promptflow copilot, we need to test it on a large set of data. The test data could be from the real user cases, like questions posted on stackoverflow. However, the test data from real user cases is usually lack of amount and comprehensiveness. Therefore, we need to generate synthetic test data to cover more scenarios. +To ensure the quality of the promptFlow copilot, it's imperative to conduct extensive testing using a broad dataset. Ideally, this dataset would consist of real user inquiries, such as those found on platforms like StackOverflow. However, real-world cases often fall short in both quantity and diversity. To address this gap, the creation of synthetic test data is necessary to encompass a wider array of scenarios. -Promptflow had prepared detailed guidelines on how to generate synthetic test data for your documents by leveraging the capabilities of LLM. For detailed steps, you can reference [this doc](../../../docs/how-to-guides/generate-test-data.md). +Promptflow has provided comprehensive guidelines for generating synthetic test data using Large Language Models (LLMs). For step-by-step instructions, please refer to the document available at [here](../../../docs/how-to-guides/generate-test-data.md). -Create a new Data asset in your workspace if your want to evaluate your copilot with the test data in azure. +To facilitate evaluation of your copilot in Azure, consider creating a new Data Asset in your workspace specifically for this purpose. ### Tips @@ -51,7 +52,7 @@ Currently, you cannot directly control how much test data you want to generate. ``` ## Step 3: Evaluate your copilot with test data -After we prepared the test data, we can use evaluation flow to evaluate the performance of our copilot againt the test data. Promptflow had prepared various of evaluation flows for different scenarios. For our RAG based copilot, we can leverage the evaluation flow in [this folder](../../../examples/flows/evaluation/eval-single-turn-metrics/). +After preparing the test data, we can utilize the evaluation flow to assess the performance of our copilot against the test data. Promptflow has developed various evaluation flows tailored for different scenarios. For our RAG-based copilot, we can leverage the evaluation flow in [this folder](../../../examples/flows/evaluation/eval-single-turn-metrics/) to ensure comprehensive and accurate performance analysis. Clone this evaluation flow folder to your local machine or upload it to your workspace. @@ -62,21 +63,19 @@ Clone this evaluation flow folder to your local machine or upload it to your wor ### Tips ``` -- The evaluation flow supports calculating multiple metrics, and have detailed explanations for each metric in the readme file. Make sure you understand each of them and choose the metrics that are most relevant to your copilot. +- The evaluation process is designed to compute multiple metrics, each accompanied by comprehensive explanations in the readme file. It is imperative to understand these metrics thoroughly and select those most applicable to your project. - The answer produced by the initial copilot flow will have a "(Source: citation)" part at the end. This is because we told the model to do that in the prompt. You can modify the default prompt to remove this part in case it affects the evaluation results as we did not append this part when generating the test data. -- The evaluation flow will give you aggregated metrics. It's important to zoom into the metrics result for each line, especially for the line with lower score. - -The bad cases usually caused by two reasons: one is the flow is not performing well, whether because the context retrival or prompt; the other is the test data is not good enough. +- Furthermore, the evaluation process will present aggregated metrics. It is essential to closely examine the results for each line, especially for the line with lower metric. +Typically, suboptimal results stem from one of two issues: either the process is underperforming, possibly due to inadequate context retrieval or prompt formulation, or the quality of the test data is insufficient. -For the first case, you can try to debug or tune the flow in local or in the workspace. -For the second case, you can try to modify the test case or abandon it from your test dataset. +To address the first issue, consider debugging or refining the process either locally or within the workspace. For the latter, you might either revise the problematic test cases or exclude them from your test dataset altogether. ``` ## Step 4: Improve your copilot flow -After evaluation, you will find that the initial copilot flow works well and can achieve relatively good metrics. We can continue improve the copilot in various ways. +After evaluation, you will find that the initial copilot flow works well and can achieve relatively good metrics. We can continue to improve the copilot in various ways. ### Improve context retrieval The context retrieval is the most important part of RAG based approach, the quality of the retrieved context will directly affect the performance of the copilot. Take a close look at the initial copilot flow, you will find that the context retrieval is achieved by 'lookup_question_from_indexed_docs' node which is using 'Index Lookup' tool. @@ -93,9 +92,8 @@ You can tune the prompt of these two nodes by leveraging the variants feature of ### Add doc link to the answer It's important to add the link of the document which is used as the context to generate the answer. This will help the user to understand where the answer comes from and also help the user to find more information if needed. -The answer produced by the initial copilot flow will have a "(Source: citation)" part at the end. But the citation is not reachable link for end user, and the source:citation format is not suitable to be shown as a hyperlink. - -To append the doc link gracefully to the answer, we can slightly modify the code of the 'generate_prompt_context' node to make the citation a reachable hyperlink. And modify the prompt of the 'answer_the_question_with_context' node to make the answer include the doc link with a proper format. The final answer will look like this: +The answer generated by the initial flow will include a citation in the format "(Source: citation)." However, this citation format does not present a clickable link, making it inconvenient for end-users to directly access the source. +To address this, we propose modifications to the code within the 'generate_prompt_context' node. These adjustments aim to transform the citation into an accessible hyperlink. Furthermore, alterations to the prompt in the 'answer_the_question_with_context' node are suggested to ensure the document link is seamlessly integrated into the response. By implementing these changes, the final response will effectively incorporate the document link in a user-friendly format. The final answer will look like this: ![doc-link](doc-link.png) @@ -107,9 +105,9 @@ Avoid abuse is a critical topic when you want to deploy your copilot to producti But what if we cannot add the authentication layer or we want to save the login effort for the users ? How do we avoid the abuse of the copilot in this case? -A common way is to adjust the prompt used in the 'answer_the_question_with_context' node to tell the model only answer the question if the answer can be found from the retrived context. But the testing result shows that even if we do so, the model will still answer the questions which are irrelevant to the context, especially when the question is a general question like "what is the capital of China ?" or chat history becomes longer. +One common approach is to refine the prompts used in the 'answer_the_question_with_context' function to instruct the model to only respond if the answer can be sourced from the provided context. Despite this, test results indicate that the model may still respond to queries unrelated to the context, particularly with general inquiries such as "What is the capital of China?" or when chat histories extend over multiple interactions. -A better way could be adding an extra LLM node to determine the relevance of the question to the copilot (in our case, the promptflow) and give a score to the relevance. Then we check the score, if the relevance score is lower than a threshold, we will skip the context retrieval step and directly return a message to the users to tell them that the question is not relevant to the copilot and suggest them to rephrase the question. +A more effective strategy involves integrating an additional LLM node tasked with evaluating the relevance of a query to the copilot's capabilities (in this scenario, referred to as 'promptflow'). This node assigns a relevance score to each query. Queries with a relevance score below a predetermined threshold would bypass the context retrieval phase, and the system would instead inform the user that their question is not pertinent to the copilot's functionality. Users would be encouraged to rephrase their queries for better alignment with the copilot's capabilities. You can find the specific code changes in the source of the promptflow copilot flow in [this folder](../../../examples/flows/chat/promptflow-copilot/). @@ -121,19 +119,18 @@ The final step is to bring our intelligent copilot to customers. Obviously, we c We want our customers to access promptflow copilot through a web page with chat UI experience, so we will deploy the flow as a managed online endpoint. You can find the detailed instructions [here](https://learn.microsoft.com/en-us/azure/machine-learning/prompt-flow/how-to-deploy-for-real-time-inference?view=azureml-api-2). ### Host web app with Azure App Service -Currently, managed online endpoint does not support CORS, so we cannot directly access the endpoint from a web page. We need to host a web app to interact with the endpoint. Azure App Service is a fully managed platform for building, deploying, and scaling web apps. You can use Azure App Service to host your web app and interact with the promptflow copilot endpoint. +Currently, the managed online endpoint does not support Cross-Origin Resource Sharing (CORS), preventing direct access from a webpage. To facilitate interaction with the endpoint, it is necessary to host a web application. Azure App Service offers a comprehensive solution for this requirement, providing a fully managed platform designed for building, deploying, and scaling web applications. By utilizing Azure App Service, you can host your web application efficiently and establish interaction with the promptflow copilot endpoint. ### Chat UI experience -The chat UI experience is also a critical part of the copilot, it will directly affect the user's experience. It's not complicated to implement a ChatGPT like UI from scratch, but it will be much easier and faster to leverage the wonderful open source projects. One of the projects we have tried is `chatgpt-lite`, we had built our promptflow copilot's UI based on it. You can find the source code of the chat UI [here](https://github.com/melionel/chatgpt-lite/tree/talk_to_endpoint_appservice). +The chat interface significantly impacts the overall user experience with the copilot, directly influencing how users interact with the system. While constructing a ChatGPT-style interface from the ground up is feasible, utilizing established open-source projects can greatly streamline and expedite the process. One of the projects we have tried is `chatgpt-lite`, we had built our promptflow copilot's UI based on it. You can find the source code of the chat UI [here](https://github.com/melionel/chatgpt-lite/tree/talk_to_endpoint_appservice). ![chat-ui](chat-ui.png) ### Provide suggested follow-up questions -Provide suggested follow-up questions is a good way to improve the user experience and communication efficiency. -A simple solution is to directly tell the model to return the follow-up questions along with the answer in the response, however this is not realiable and increase the complexity of processing the response. Another solution is to use another flow to do the follow-up question generation task. You can leverage the 'question_simulation' flow in [this folder](../../../examples/flows/standard/question-simulation/) to generate the suggestions for the next question based on the previous chat history. +Incorporating follow-up question suggestions is an effective strategy to enhance user experience and communication efficiency. One approach is to instruct the model to include follow-up questions in its responses. However, this method may not always be reliable and could complicate response processing. An alternative strategy involves utilizing a separate flow dedicated to generating follow-up question suggestions. For this purpose, you can employ the 'question_simulation' flow found in [this folder](../../../examples/flows/standard/question-simulation/). -Deploy the `question_simulation` flow as a managed online endpoint and call it in your web app to get the follow-up questions. +Deploying the `question_simulation` flow as a managed online endpoint and integrating it into your web application allows for dynamic generation of pertinent follow-up questions based on previous chat interactions. ### Tips ``` From 121df0c13c9fd748480cac508eb9ea28f2a10fa5 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 8 Apr 2024 16:52:15 +0800 Subject: [PATCH 092/112] modify links for gen test data doc --- docs/how-to-guides/generate-test-data.md | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index c56bdbe22a3..db9f9f1b7eb 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,12 +18,12 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder and install required packages. +2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages. ```bash pip install -r requirements.txt ``` - + For specific document file types, you may need to install extra packages: - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` @@ -32,52 +32,52 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 3. Install VSCode extension `Prompt flow`. -4. Create your AzureOpenAI or OpenAI connection by following [this doc](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection). +4. Create your AzureOpenAI or OpenAI connection by following [this doc](../how-to-guides/manage-connections.md#create-a-connection). 5. Prepare test data generation setting. - - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - - Prepare `config.yml` by copying [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). - - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: + - Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. + - Prepare `config.yml` by copying [`config.yml.example`](../../examples/gen_test_data/config.yml.example). + - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: - Common section: this section provides common values for all other sections. Required. - Local section: this section is for local test data generation related configuration. Can skip if not run in local. - Cloud section: this section is for cloud test data generation related configuration. Can skip if not run in cloud. > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. - > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to open [example test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/flow.dag.yaml) in visual editor and set `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to open [example test data generation flow](../../examples/gen_test_data/example_flow/flow.dag.yaml) in visual editor and set `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. ## Generate test data -- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - +- Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. + - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run - ``` + ``` - The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. -If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. +If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](../../docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. ## [*Optional*] Customize test data generation flow -- Open the [example test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. +- Open the [example test data generation flow](../../examples/gen_test_data) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. -- Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). +- Customize your test data generation logic refering to [tune-prompts-with-variants](../how-to-guides/tune-prompts-with-variants.md). **Understanding the prompts** - + The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. + - [*generate question prompt*](../../examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](../../examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. - - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + - [*score text chunk prompt*](../../examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. + - [*validate question prompt*](../../examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](../../examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. -- Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). +- Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](../how-to-guides/init-and-test-a-flow.md#visual-editor-on-the-vs-code-for-prompt-flow). Once the customized flow has been verified, you can proceed to batch generate test data by following the steps outlined in ["Prerequisites"](#prerequisites) and ["Generate test data"](#generate-test-data). \ No newline at end of file From 95b443abd0bde1ee035811bf90878470cdd8c98b Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 8 Apr 2024 16:55:14 +0800 Subject: [PATCH 093/112] add readme file for copilot flow --- examples/flows/chat/promptflow-copilot/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/flows/chat/promptflow-copilot/README.md diff --git a/examples/flows/chat/promptflow-copilot/README.md b/examples/flows/chat/promptflow-copilot/README.md new file mode 100644 index 00000000000..fae6bfa70c6 --- /dev/null +++ b/examples/flows/chat/promptflow-copilot/README.md @@ -0,0 +1,5 @@ +# Promptflow copilot + +A chat flow used to build copilot for promptflow. + +Please reference [this doc](../../../tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md) to see how we build this flow step by step. \ No newline at end of file From 7b15352e0c2ef9abcd49600ccab065ef245ea833 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 16:41:54 +0800 Subject: [PATCH 094/112] add tutorial to index --- docs/tutorials/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index 8e053fb2010..0461d826b51 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -11,7 +11,7 @@ This section contains a collection of flow samples and step-by-step tutorials. |CLI|[Working with connection](https://github.com/microsoft/promptflow/blob/main/examples/connections/README.md)| Manage various types of connections using cli |SDK|[Run prompt flow in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/get-started/quickstart-azure.ipynb)| A quick start tutorial to run a flow in Azure AI and evaluate it. |SDK|[Flow run management in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/run-management/cloud-run-management.ipynb)| Flow run management in azure AI - +|SDK|[Develop promptflow copilot](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md)| A step by step guidance to develop a promptflow copilot. ## Samples @@ -23,8 +23,8 @@ This section contains a collection of flow samples and step-by-step tutorials. |Standard Flow|[customer-intent-extraction](https://github.com/microsoft/promptflow/tree/main/examples/flows/standard/customer-intent-extraction)| a flow created from existing langchain python code |Standard Flow|[web-classification](https://github.com/microsoft/promptflow/tree/main/examples/flows/standard/web-classification)| a flow demonstrating multi-class classification with LLM. Given an url, it will classify the url into one web category with just a few shots, simple summarization and classification prompts. |Standard Flow|[autonomous-agent](https://github.com/microsoft/promptflow/tree/main/examples/flows/standard/autonomous-agent)| a flow showcasing how to construct a AutoGPT flow to autonomously figures out how to apply the given functions to solve the goal, which is film trivia that provides accurate and up-to-date information about movies, directors, actors, and more. -|Chat Flow|[chat-with-wikipedia](https://github.com/microsoft/promptflow/tree/main/examples/flows/chat/chat-with-wikipedia)| a flow demonstrating Q&A with GPT3.5 using information from Wikipedia to make the answer more grounded. -|Chat Flow|[chat-with-pdf](https://github.com/microsoft/promptflow/tree/main/examples/flows/chat/chat-with-pdf)| a flow that allow you to ask questions about the content of a PDF file and get answers. +|Chat Flow|[chat-with-wikipedia](https://github.com/microsoft/promptflow/tree/main/examples/flows/chat/chat-with-wikipedia)| a flow demonstrating Q&A with GPT3.5 using information from Wikipedia to make the answer more grounded. +|Chat Flow|[chat-with-pdf](https://github.com/microsoft/promptflow/tree/main/examples/flows/chat/chat-with-pdf)| a flow that allow you to ask questions about the content of a PDF file and get answers. |Evaluation Flow|[eval-classification-accuracy](https://github.com/microsoft/promptflow/tree/main/examples/flows/evaluation/eval-classification-accuracy)| a flow illustrating how to evaluate the performance of a classification system. Learn more: [Try out more promptflow examples.](https://github.com/microsoft/promptflow/tree/main/examples) From 2b7d4fa5daf9a25923cfcf71025d217ff7e7b613 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 16:44:32 +0800 Subject: [PATCH 095/112] fix flake error --- .../flows/chat/promptflow-copilot/check_relevance_score.py | 2 +- .../flows/chat/promptflow-copilot/generate_prompt_context.py | 2 +- examples/flows/chat/promptflow-copilot/select_prompt.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/flows/chat/promptflow-copilot/check_relevance_score.py b/examples/flows/chat/promptflow-copilot/check_relevance_score.py index 27cfebbec96..88e28fb0aba 100644 --- a/examples/flows/chat/promptflow-copilot/check_relevance_score.py +++ b/examples/flows/chat/promptflow-copilot/check_relevance_score.py @@ -1,6 +1,6 @@ - from promptflow import tool + @tool def my_python_tool(score: str) -> str: return score == "0" diff --git a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py index 90345610e22..213cacb5824 100644 --- a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py +++ b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py @@ -6,6 +6,7 @@ from promptflow_vectordb.core.contracts import SearchResultEntity import re + @tool def generate_prompt_context(search_result: List[dict]) -> str: """Generate the context for the prompt.""" @@ -31,7 +32,6 @@ def format_doc(doc: dict): if URL_KEY in entity.metadata[SOURCE_KEY]: source = entity.metadata[SOURCE_KEY][URL_KEY] or "" - # source = source.replace("azureml://locations/eastus2euap/workspaces/c3a40c81-f452-449b-b62e-ba25cf5b6029/data/vector-index-input-1705993805833/versions/1/community", "https://github.com/microsoft/promptflow/blob/main/docs") source = re.sub(pattern, replacement_text, source) retrieved_docs.append({ "Content": content, diff --git a/examples/flows/chat/promptflow-copilot/select_prompt.py b/examples/flows/chat/promptflow-copilot/select_prompt.py index c88326c7230..b8eca1e5097 100644 --- a/examples/flows/chat/promptflow-copilot/select_prompt.py +++ b/examples/flows/chat/promptflow-copilot/select_prompt.py @@ -1,8 +1,9 @@ from promptflow import tool + @tool def my_python_tool(answer_question_prompt: str, refuse_prompt: str, not_relevant: bool) -> str: if not_relevant: return refuse_prompt - return answer_question_prompt \ No newline at end of file + return answer_question_prompt From 3968ee8337473e2c8d37a8323a492da72840a853 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 16:46:43 +0800 Subject: [PATCH 096/112] fix flow yaml schema --- examples/flows/chat/promptflow-copilot/flow.dag.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/flows/chat/promptflow-copilot/flow.dag.yaml b/examples/flows/chat/promptflow-copilot/flow.dag.yaml index e10ca0581c9..b1310b99ed7 100644 --- a/examples/flows/chat/promptflow-copilot/flow.dag.yaml +++ b/examples/flows/chat/promptflow-copilot/flow.dag.yaml @@ -1,3 +1,4 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json inputs: question: type: string From c5b0035ad4f71b16210dfef456d3408065603ace Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 17:06:46 +0800 Subject: [PATCH 097/112] update document --- .../develop-promptflow-copilot/chat-ui.png | Bin 250504 -> 227020 bytes .../develop-promptflow-copilot.md | 9 +++++++-- .../mir-options.png | Bin 9912 -> 14906 bytes 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/tutorials/develop-promptflow-copilot/chat-ui.png b/examples/tutorials/develop-promptflow-copilot/chat-ui.png index ed5a5a2714c9d40ca228d746a763c190d2260918..720608a61f025f53aa1df1c8ae40b9e722cb9272 100644 GIT binary patch literal 227020 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 x!9lqmpCFaQeiGn=tw_=pI$YS4=u0@y~N7d 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

->~Ao)jeV#i6iI!RV+2 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 MzPTRu=G`a%2g58~c>n+a literal 250504 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

lIK-|Mq841c#$7j&`w70-z1+Ap?Iu2YK{ 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

8csze8fD5h|=$*CQ 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

p#5qsrI0W|mU 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�N&$oDVlqeqXB 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∨ITqx3y<_1Cred9-qqik|qv&dy_bdH9Azky+Ps zm^O~d4-;W8ba2!Kg@m+J)iZujVfqXT4KoSdrI{JTY9FHdhQG&j)t=GQ`An;>and=} zCXDn&6)^?P=VCiD-J7_OFO6L(1jvRBVuFOGN-R?gpr3$f+#(pCu~oN++Xa(|^0 z&As>a5&|v#!;|*_xvBU;+T(eH;wBIenetuX&vTd4D|>&YIEA93PXltcl^2!j#m+Aw z@~_Tyr$o%4OyRpyTKSJ;E+gv61N~cZE+G(xf7#7L-T(L33%r+v%1Vx@p31<05c1MW KQh7+jxBmsTpim$H From def4be70b0693806645e9f3ef966ed9f3c4c4680 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 18:05:29 +0800 Subject: [PATCH 098/112] add vectordb to requirements --- examples/flows/chat/promptflow-copilot/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flows/chat/promptflow-copilot/requirements.txt b/examples/flows/chat/promptflow-copilot/requirements.txt index 8b137891791..a72ea5f0733 100644 --- a/examples/flows/chat/promptflow-copilot/requirements.txt +++ b/examples/flows/chat/promptflow-copilot/requirements.txt @@ -1 +1 @@ - +promptflow-vectordb==0.2.8 \ No newline at end of file From 144fb7277010c99b95ef26cdde7bbadc4241bd0d Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 18:07:40 +0800 Subject: [PATCH 099/112] update image --- .../develop-promptflow-copilot.md | 2 +- .../mir-options.png | Bin 14906 -> 5109 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md index a052018c2d5..7c2015fc319 100644 --- a/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md +++ b/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md @@ -139,6 +139,6 @@ User feedback is invaluable for enhancing the copilot's performance and user exp When you deploy the flow as a managed online endpoint, you will find the endpoint has provided two POST APIs if you check the endpoint's swagger: `/score` for trigger your copilot flow with inputs and `/feedback` for collecting user feedback into the trace data. ``` -- You are recommended to turn on this options when you deploy the MIR endpoint, so that you can collect the related data and calculate online metrics. +- You are recommended to turn on this options when you deploy the MIR endpoint, so that you can collect the related data and calculate online metrics to your workspace's application insights. ``` ![mir-options](mir-options.png) diff --git a/examples/tutorials/develop-promptflow-copilot/mir-options.png b/examples/tutorials/develop-promptflow-copilot/mir-options.png index ce216561299b10f11ccd52e568e8aea024a93da7..7129d57a8639a22bf5fcc45b19f99a85afcba29f 100644 GIT binary patch literal 5109 zcmcgwXIGO!w?#w{6%l!r-W3EydJ!Zby(mZ#5J&)#-aAq)Akw8vNodjuNJ&BqNH0OE z^bSIV(0k_&?_aog-4Dr{l|1vz%sKn)z0ZWc(om+jL4SjYh=@W}MM0a0=n4dkjjxk} z?*q57AtEB`I#q?|y54DPQ+BU(@l5So{KP!sjS3cu^9p1Gk&iI5|3*J#lG3Suj`^b` zB0JzyU|3WYGddcomfB~a(tsQ zwKQ`!as~aAxa%i(J)GnJXebt4LoD|-M6+}xE;(7%#YHerGhHc1dv0YVOf839Qj$JF zZ7;vbT6jZ8xwtG&170*mbW2TH6Mf@;Wx|iDVEr!1{BlQ6_*9 z3v(K%k-lNc;sTxaI=Z_bh=^1U zCc@m^MFa%}nR1JCdF15fJG;9@Y^Ip6RZ!M{`b4Z0LEBi-3kgq3qDc=te@goKd2)JM zTKAsA^heen2k#K6G7?UT!w`R(>AlaP>P=oN)VMp`Tn zcJLO?&^jnHk&M+#J|$9Txk3 z1A8Dj6*VxRZ6QN;?b=pv;CaQ=>BUSblqm^eAMP@tUkXFotINs~`R=c3)ttS4{kqts z0XF8;*x1Mj@iRzvvY(a>Pu0GA_wEs10Zak0exKA{n78XA4S_(Q zJzgFjYwk7C(Uh&Nt4YZZNRd! zvcO?}R97bl1(B2(S7-Sxft=CaA_WKQJU!Y`)zq}wn8qF;o$qGG}2~A8qP(ndeYdqxkI^ia=*pKeyXjN%FN76d-gtdc6Qct z5nWmN({AKRY+M}J$n6kHmZc$mlf}MF`3Dak^i59Ql7&KH6-MBnGJs)s!nG4W%bac$dX+q3~3SYmow7g48J8F|e`1SFs-)19O zP*Bjfn3#`X^`oOBCWzO33ppsTF_aw*3%BiZ7U$Trz1EQ%(PRxE(*2hPZnVH#sypkNLrw(e6oSan!0xt4hGa<(9y&U@Vi=Y_qrJV57x3k}(4mm9aIO7Nbxn;n z6gsuAck4fv{wyY7sU&_APC%l(yu6$*Q(CHA7CO4R*a2;U9~LV>%1rlH$B6z64{z^J zIO!M~cExk+d>D2r5w#mOb#m$rBBz${KNblN4i*s+aW@KCUA5=oQo;Z9)1%PE?~&|qoq_&i^G$X z3fm!`w6wJE;!ezfP&4Z4(p2L(1zrED6c-o )+jv{81biShBfckd3^-1!d;job3T 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 Vchc%VaGgh_s;Hq*B4_&Pe*lgbYPJ9X literal 14906 zcmbVzbySpX^zG0fNJ>bzfYRL|ASwt*N=S)-bT`tCh=PaHmz0EbNebLE z-|ybL?%#JU7COVs8|OLCIs5Fr-w3rQ4{qL|yn#R%336(tVGoKG;1WM3*I0?D*VtlO8*e9@|U?^#Q!& z@=$33UWRi;JoBcKA>_;TxDh0FxNr z`3)^+^q6n4^mt)h>aXnP_4To7aHxkFEFXneCcO72lAjs=sQvMvUIiz+O#Th}8%uW= zNr9B!BSS?(`I%Picp-J`uT?Ma#lgX*(d!J}9IpLX?ulcneSIzUwV+_QNMHD9cb<;B z6j$$yhB~FF{nje_Ride7AqcqNR)KD`Ig&xtDl}EMbA1Bweg`@8VJk+o31+ zby}A+VGXt(+o6fRc}oZ*R)tlgatfACEsdi30U}w{Bp(p_6{Y^x%zgXC$e|PTd-15mRDc zrW)I1tXEy`b(Jim5}`_V$&e)p7k*fWUnNdjnL=?#1KZ=rkN3|vOVAL_7dzsUQ&UwH z3fBfdYkWe=FFYy!uB>?#UH|@0vNctKRnmOUk*l1X?an73 zRN7dqgW&(e&i*(gsx@j+lse9kIFX%tok6ouNxfNyYRYKDo0rC_LYuTSD@xuh)_F z=q6qg-|hC>CF_MJOPx`r<>l?)B1p78kl(sxe0ly?x5-P8nuZ2NV0Ik^1*O*OF9+B2 z#&C9x+|ngYBO`)3gTX6vsp<1|rBUqmQ%mazUQVG^vsbTruguYl*yH%)_b#*1cYa7; ze=E|jSy)?}_?7Fz=H%o=AE%_LC*Lb_e%99CODQbm6MDY!3eT|m)*HW=5Vhp#X+47` zFH#a#W&gUmx>vq$-b~iJT4&q#4-D|y&5C>!cgKgT;o;{u>ntoT#zz>Nn`1aTAL5e^ zCD3DQ!MeS&wpQ2D3aPIbOG-}8ujLq17}RyCcM&C^m1x~t?BI3ZF|e5|MQQRr=^9a$ zjg94t9kTG4c4GyTpI^@OAQ~ zN#Feyy4P~g^>In~`6UJ$!|aZa#Y#rr-%(Y2{v1D3?Mt~qrdmd6DWQGKrO*vr+$r;Z zBOM)`_=E)H2@7k-CMM7j9uloHL zA|irEP*B0f=HBewT$$~R&}_XcZb(ST=|T_zEJ{dUBDdMvU>d@o+{lOM&XbS+QBk<# zh0lU;$+=obMo3yNkEsF!1K*~nzX=b={`~nfJtL#s%5PdJAByz!^wY&KI%6}lAWr>i z_h0mKPh3$XY zxZHz~78G=h7wMNdE-Nah3f&a8n{EAfc1T1+6C-Fno{^iYxOgV(K{ofvSP zt#4?=jjgQ<%58nMNN<#|E>8(tn5~!Ryj}U7Ro!T?c7;qZBcoWmx%xi_s+X+QrKK{y zzLKwAy_)o^IY0N()zf=dN+f>=0@wQU=Q~o7)nrUPDWyVD7d`TvPoL<>xS!*3B}NSm zsWqN&6u|N+mOO8obcJy9xNc}R?zQ8VmX`Vl1))K1)EaO>O@igvEUKCOdtXk@;rz%- zDd%Z*2s%O|SGjGoqy-DbKsVPC2H@-^}V#t-)v??aNA{`~wDk$F;J{v=xNW;(7h`cH;^K#)VPRn<9CjPOvWkdH6)w9zNjvp&?pSY$oj@y^!*9zS@Qcv)NilB^8x1JykC+F)~iQU?L_(kmuQ$@0=t;DcCNS;n|8_iAct9>6x|G3&y6VPV0<%^iE$|4G_t*9#pL zg_@e$VfUBhI8DA9+ur&xlZc3j3_W3Me?Oj(kPzG5yJme=H_5CXBMYMGH*91DetJJf6M#i7YV6p^Q-YT7Cv=r zt>f}giIFt2$zNWabi?5s;Se@+^;&DjWGYasGb<}^O_UgQN08j1fB!wDs!6CT`gTxn z?;~bb*01;6U0lBD82NTSAwp2vEq(hY-}8bmno_Wr{^AaHmRa`0Exf77O(#?fD=VBb z-RL-`2c}z-Wjw;d-MK2ML)i}q@NV;=moy&SK=yUgyV|YazvCcVu;100MKql>t%8EW z-qF#hx6%DD{LY=ZhT$e}_j}LE(c9YE-ag8KO4kW3a)18%iX866Uybcs%k`zbrnYu_ zSC`_h7bN-K@B=yq2?^>j0=lkJla9UZnt4WeN#}b+gsk#-w*wWT$QZ=MsYY^Df^_dG z%E-u63{D;W8Cl%ijB=m%C6|WPsi+NI;i?rCqF@@ju__EP$1 zQCsw3K{dbJ7)~3!TVJDi#GXBS79Jk%pOeEPCnvYCxQK#_i>s-l!z3w5gGE3qucbxW z-qEqRwA5bDy1B8Trmr6b4K^mo2=aqk!s`fob#)bD6qcNPTUl9IQ_d5`^2jjx!*QE? z9U1lTzVRwMCMG7Mm>4C5!Q<*|jfk2$dVSpz9p2>Nh$I#MJGeI9I29q!=;7^spY4_$ z+bu>0hRpA_Sy@?xq@)-KYyyG_>(n=anj8w2mTaG&=F4v25)fGY2;o(enh0fOU_g<} zB+Sgr#B^>T;k-Y>KS#~2^7u8H*tP&lma~beX&?>>t8sfU4x(~?ueZ|eg%&i(rKKf8 za&oKy8AJv{dcHEN*_{l^_j`K|rxzDy2fx27&L?K7)p#DR4s6?~2dS~Jun6{%B`b%X zo_c)y_N}$AuP=O@=saV$!e)J)70_;K_79a`dXDcO zU1=M)l4=ky-;h<1T_?zxn4XR=^{Ir>ZX-A>tfKg_@2oCgG9Fw%0w4jgu1+w$_toXJ!4DBJ}i##l=O$m0Jx?h#WF(%*6Slo$=d~WkH7N zZ{N1smHc__YoqNp{L1-+&u)0P`J(utPALRXMh4;C59gqa4HBip!NGx(-1qU3@Sd$7 z#BfeS*2mAEnS+CaOYPKrf8;AMw+CY2mRgOl9{=j;?|-qaEfvI*r-4?DtB{4sLGadV~LZ zpen-8>FKF4fE~Sw#P2V3n|(yv+uP~Mq8u07F(AS+90}#VO3H?hKiq3u9Y`gjpa}2j zQQDfRQO$mQv_70|<0~sG%fVF(ph^D012b4BB_*ZS51jfA@O?PA&3rS>=0u4F20a(o z8_wm!Gn;5tLxG8xaZ14ncXdoJj<>h=cc-hOE*CkW>}=1}FpxzN-M$@>l$4~H#Razm zkRKfbL-rmS6Xfmp@850C-myH^^#-s(NJSL|7>9|Ek2oM809s2(Vj?-KYI=Y1$$mE- z6DzBtxwHf=!A!MnP)m!nsi|q{i|_AVrfDFcbYW6`@&B=A_Wd18_?tIf0KNdnQsNB4 z4YjQ}#U&@>WGrIz0fIoo!vB_~5Vf$p+%a9~bLFb8tBWo5=?AU5#e<1M+rr_W$N{T$ z$ljTYi%ai*GOu)Ful*A2E;bI1pJF2SS>Gc|1Oo#D;f)XqakqPZ*O%@u%*`2?n9$(O zfojL&t*I@7#Ph45z`)7zJbA{ppE-}GuA3Sg7ofcy9UUo}!@)QXajR$^JKJ(`aI`~( zdFG9Qit_LBa>_IN&6_t{XGeQ`#wXd$MpB<*rz$KeTp?U#E4@Vxuuf?cu~tNY;xfN{ zQ7VyTK2O&`AaSa7UPT3e17~dah)7mq_p-@QhV0gv(xXR#EiJFJ%`hqDP+z`yVfm4y zAR0P&U{Fx1MDd`ae&sBM(n2_X7(@HX-kFaQGjUK1D>|j0Lz1u`l<3h>O+d|Ajg1C* zcSn;1?$ELaDYIIWr{+9m@2x`r^WjmBZledUkj-RkHL74+Egirg$TA`ll8(?VYkN3J z-23+()k})8v~z=GuGG;q?;cY@a2t%bs6Ki!8Pz$lT(}|A+iGN9Hao#E5D>lC#TJEo znv))5MkZE4goK2y@JA=f=%}ZLzu&)m zr)R_e=|^|0^i@y&>gT8I@7}#z*xW2|r-9X$_w*FyGOYhLPDD=L?Pp=5QLRM-x47YCZnzW-sxr1Yvz&?c3F%`ek zc>2`kxNYA$I;O-1~d1|MCVZne9oHY1uDXTiyVe3OQ&m?1QgZO2)o|U;AX0Y zBgcrp8)Jmn=t&Zue5XEA-qBEF3Zvc;dA<}kPqD6mEdnh>%b*f=s+0&NkmmO7+nlf3{)pujwM|TrTl`2jH;hWz zp+eZS7%M4ZXJu!@eU$lKp1U2QS7O-yNqLc>#2P$2>|$n}dh{LrMNvtK#bNu{_;~rB znED&h89dT1@)H>>&c|0c5NkW>~4>zbuZ0d4zF`qnnvTZ6ZOIUPATAGfGjLfEVrJ7iT@`c?0 z%iZ7rk7APXI~RTbNBiUt2^{MESQ*Ju+s8aFcgkOLD8IEZGhL_lEDCTMt>Q%1k5E0= z^EUa`iR0`kb&?uB+4O*}DSW;A4- z)f?}e%D!d_J-8bnN4H|t#OkA;AC@1_t*{bDAZJLWoS%xWcbJ(=MTbV6{qomdnQc5B z)abHdB916^Sd?RCVQCu~sZj4z&`1}yt(zOQ${*-mQ%RlcKZ}fv{F!v3qLY?#&|oG0 zoK@T0)HJJWS*uyK(r`C-2iI`Ix-Af6@8qQWqo}i{)2QIu>Cu3C-gfh-3*N>_e)XE{ zWvv(q@?zzgiA^Bc!XqLA04Et6)7#C~wtd)!38&@X0q!?b-Va=cUy1epv<9F-Eq>`7 zz>d|6arMTsguOe_YdRHxYuo(%rx@OzQ5q7GAeihBmObBvypL^!N}hRmh(IBPmJ#>i zLuhm~-Z7SusOs&C7|8N!`+5A=uU~)8$q`JkEKFbH5b&B(u-6BQ>N$@~^Dx46*iSOlQIS%3Fsjhjl+O8^Lgt`EFL zG%BK<@rS{@bq(?JV=~;nwS0G_Vg~rzg(`9YKx_It

p#5qsrI0W|mU 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�N&$oDVlqeqXB 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 Date: Tue, 9 Apr 2024 18:53:24 +0800 Subject: [PATCH 100/112] add vector db to examples requirement --- examples/flows/chat/promptflow-copilot/requirements.txt | 2 +- examples/requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/flows/chat/promptflow-copilot/requirements.txt b/examples/flows/chat/promptflow-copilot/requirements.txt index a72ea5f0733..cd05c963703 100644 --- a/examples/flows/chat/promptflow-copilot/requirements.txt +++ b/examples/flows/chat/promptflow-copilot/requirements.txt @@ -1 +1 @@ -promptflow-vectordb==0.2.8 \ No newline at end of file +promptflow-vectordb \ No newline at end of file diff --git a/examples/requirements.txt b/examples/requirements.txt index 21832de3282..40b87fc4006 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -1,4 +1,5 @@ promptflow[azure] promptflow-tools +promptflow-vectordb python-dotenv bs4 From ce376aa6473774f93918e0a638c77c1151c82e29 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 9 Apr 2024 19:01:32 +0800 Subject: [PATCH 101/112] update doc link --- docs/how-to-guides/generate-test-data.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index db9f9f1b7eb..2a034e4fc2f 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,7 +18,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages. +2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data/) folder and install required packages. ```bash pip install -r requirements.txt @@ -32,10 +32,10 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 3. Install VSCode extension `Prompt flow`. -4. Create your AzureOpenAI or OpenAI connection by following [this doc](../how-to-guides/manage-connections.md#create-a-connection). +4. Create your AzureOpenAI or OpenAI connection by following [this doc](manage-connections.md#create-a-connection). 5. Prepare test data generation setting. - - Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. + - Navigate to [example_gen_test_data](../../examples/gen_test_data/) folder. - Prepare `config.yml` by copying [`config.yml.example`](../../examples/gen_test_data/config.yml.example). - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: - Common section: this section provides common values for all other sections. Required. @@ -48,7 +48,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene ## Generate test data -- Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](../../examples/gen_test_data/) folder. - After configuration, run the following command to generate the test data set: ```bash @@ -57,11 +57,11 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. -If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](../../docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. +If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](../cloud/azureai/generate-test-data-cloud.md) for more detailed steps. ## [*Optional*] Customize test data generation flow -- Open the [example test data generation flow](../../examples/gen_test_data) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. +- Open the [example test data generation flow](../../examples/gen_test_data/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - Customize your test data generation logic refering to [tune-prompts-with-variants](../how-to-guides/tune-prompts-with-variants.md). From e29fbbc3695008eed14219432094497604bbe0a4 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Wed, 10 Apr 2024 10:33:06 +0800 Subject: [PATCH 102/112] import tool from core --- examples/flows/chat/promptflow-copilot/check_relevance_score.py | 2 +- .../flows/chat/promptflow-copilot/generate_prompt_context.py | 2 +- examples/flows/chat/promptflow-copilot/select_prompt.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/flows/chat/promptflow-copilot/check_relevance_score.py b/examples/flows/chat/promptflow-copilot/check_relevance_score.py index 88e28fb0aba..45aa8fbdb12 100644 --- a/examples/flows/chat/promptflow-copilot/check_relevance_score.py +++ b/examples/flows/chat/promptflow-copilot/check_relevance_score.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool diff --git a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py index 213cacb5824..1583a6a1edb 100644 --- a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py +++ b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py @@ -2,7 +2,7 @@ # Licensed under the MIT License. """File for context getting tool.""" from typing import List -from promptflow import tool +from promptflow.core import tool from promptflow_vectordb.core.contracts import SearchResultEntity import re diff --git a/examples/flows/chat/promptflow-copilot/select_prompt.py b/examples/flows/chat/promptflow-copilot/select_prompt.py index b8eca1e5097..8b29846adfc 100644 --- a/examples/flows/chat/promptflow-copilot/select_prompt.py +++ b/examples/flows/chat/promptflow-copilot/select_prompt.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool From 1523d415322474efc123a2e79ed4f644d18a1add Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Wed, 10 Apr 2024 11:05:58 +0800 Subject: [PATCH 103/112] use PR link for now --- docs/how-to-guides/generate-test-data.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 2a034e4fc2f..9517f535575 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,7 +18,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data/) folder and install required packages. +2. Prepare local environment. Go to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/) folder and install required packages. ```bash pip install -r requirements.txt @@ -35,8 +35,8 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 4. Create your AzureOpenAI or OpenAI connection by following [this doc](manage-connections.md#create-a-connection). 5. Prepare test data generation setting. - - Navigate to [example_gen_test_data](../../examples/gen_test_data/) folder. - - Prepare `config.yml` by copying [`config.yml.example`](../../examples/gen_test_data/config.yml.example). + - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/) folder. + - Prepare `config.yml` by copying [`config.yml.example`](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/config.yml.example). - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: - Common section: this section provides common values for all other sections. Required. - Local section: this section is for local test data generation related configuration. Can skip if not run in local. @@ -44,11 +44,11 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. - > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to open [example test data generation flow](../../examples/gen_test_data/example_flow/flow.dag.yaml) in visual editor and set `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to open [example test data generation flow](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/flow.dag.yaml) in visual editor and set `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. ## Generate test data -- Navigate to [example_gen_test_data](../../examples/gen_test_data/) folder. +- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/) folder. - After configuration, run the following command to generate the test data set: ```bash @@ -61,7 +61,7 @@ If you expect to generate a large amount of test data beyond your local compute ## [*Optional*] Customize test data generation flow -- Open the [example test data generation flow](../../examples/gen_test_data/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. +- Open the [example test data generation flow](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - Customize your test data generation logic refering to [tune-prompts-with-variants](../how-to-guides/tune-prompts-with-variants.md). @@ -69,12 +69,12 @@ If you expect to generate a large amount of test data beyond your local compute The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - - [*generate question prompt*](../../examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - - [*generate suggested answer prompt*](../../examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. + - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - [*score text chunk prompt*](../../examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. - - [*validate question prompt*](../../examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](../../examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. + - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. From ba3a3aefa3215b8f39a83264efdb281bdf1ae231 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Wed, 10 Apr 2024 11:26:50 +0800 Subject: [PATCH 104/112] remove unknow field --- examples/flows/chat/promptflow-copilot/flow.dag.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/flows/chat/promptflow-copilot/flow.dag.yaml b/examples/flows/chat/promptflow-copilot/flow.dag.yaml index b1310b99ed7..3d8f71a6d6b 100644 --- a/examples/flows/chat/promptflow-copilot/flow.dag.yaml +++ b/examples/flows/chat/promptflow-copilot/flow.dag.yaml @@ -11,7 +11,6 @@ outputs: output: type: string reference: ${answer_the_question_with_context.output} - evaluation_only: false is_chat_output: true nodes: - name: modify_query_with_history From 14cc9aafaaa96156253e15a0039f48f991d01217 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Wed, 10 Apr 2024 11:27:08 +0800 Subject: [PATCH 105/112] use PR link for now --- docs/tutorials/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index 0461d826b51..078b57620d6 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -11,7 +11,7 @@ This section contains a collection of flow samples and step-by-step tutorials. |CLI|[Working with connection](https://github.com/microsoft/promptflow/blob/main/examples/connections/README.md)| Manage various types of connections using cli |SDK|[Run prompt flow in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/get-started/quickstart-azure.ipynb)| A quick start tutorial to run a flow in Azure AI and evaluate it. |SDK|[Flow run management in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/run-management/cloud-run-management.ipynb)| Flow run management in azure AI -|SDK|[Develop promptflow copilot](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md)| A step by step guidance to develop a promptflow copilot. +|SDK|[Develop promptflow copilot](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md)| A step by step guidance to develop a promptflow copilot. ## Samples From 78433a1ae128120b063a4362e6a0b0d5525389be Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 23 Apr 2024 18:52:26 +0800 Subject: [PATCH 106/112] add to index.md --- docs/cloud/index.md | 1 + docs/how-to-guides/index.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/cloud/index.md b/docs/cloud/index.md index eb52309135a..f6d53d9e6e1 100644 --- a/docs/cloud/index.md +++ b/docs/cloud/index.md @@ -34,6 +34,7 @@ azureai/manage-flows azureai/run-promptflow-in-azure-ai azureai/create-run-with-automatic-runtime azureai/use-flow-in-azure-ml-pipeline +azureai/generate-test-data-cloud.md ``` ```{toctree} diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index 821b9a0a860..52259816e5b 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -14,6 +14,7 @@ tracing/index develop-a-flow/index run-and-evaluate-a-flow/index execute-flow-as-a-function +generate-test-data ``` ```{toctree} From e268845d10dcf1445d8ee04a149c94fc3f8643b7 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Fri, 26 Apr 2024 16:19:07 +0800 Subject: [PATCH 107/112] fix doc --- docs/how-to-guides/generate-test-data.md | 2 +- docs/how-to-guides/index.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 9517f535575..ee406d6d63b 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -78,6 +78,6 @@ If you expect to generate a large amount of test data beyond your local compute If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. -- Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](../how-to-guides/init-and-test-a-flow.md#visual-editor-on-the-vs-code-for-prompt-flow). +- Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](../how-to-guides/develop-a-dag-flow/init-and-test-a-flow.md#visual-editor-on-the-vs-code-for-prompt-flow). Once the customized flow has been verified, you can proceed to batch generate test data by following the steps outlined in ["Prerequisites"](#prerequisites) and ["Generate test data"](#generate-test-data). \ No newline at end of file diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index 86492af8199..cb10915c59b 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -20,7 +20,6 @@ develop-a-prompty/index develop-a-flex-flow/index develop-a-dag-flow/index execute-flow-as-a-function -generate-test-data chat-with-a-flow/index run-and-evaluate-a-flow/index generate-test-data From 7321082cbcb6d463108a72d03a7475aa41927e12 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 6 May 2024 22:29:00 +0800 Subject: [PATCH 108/112] fix doc link --- docs/cloud/azureai/generate-test-data-cloud.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index bc1eeed1f03..10573dcf1ea 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -17,7 +17,7 @@ This guide will help you learn how to generate test data on Azure AI, so that yo 4. Prepare Azure AI resources in cloud. - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). - A compute target - [Learn more about compute cluster](https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2). -5. [Create cloud AzureOpenAI or OpenAI connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start/index.html#create-necessary-connections) +5. [Create cloud AzureOpenAI or OpenAI connection](https://microsoft.github.io/promptflow/cloud/azureai/run-promptflow-in-azure-ai.html#create-necessary-connections) 6. Prepare test data generation setting. - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. @@ -31,6 +31,6 @@ For handling larger test data, you can leverage the PRS component to run flow in - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run --cloud - ``` - + ``` + - The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. From 0dca96ac44205899badafc0d2f15285d6aebbfce Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Tue, 7 May 2024 17:31:37 +0800 Subject: [PATCH 109/112] run readme --- .../samples_flows_evaluation_eval_multi_turn_metrics.yml | 9 +++++++++ ...samples_flows_evaluation_eval_single_turn_metrics.yml | 9 +++++++++ .../samples_flows_standard_question_simulation.yml | 9 +++++++++ docs/tutorials/index.md | 2 +- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml b/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml index e669bdb58bf..f3944040ce7 100644 --- a/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml +++ b/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml @@ -48,6 +48,11 @@ jobs: sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example mv .env.example .env fi + 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/evaluation/eval-multi-turn-metrics run: | @@ -74,6 +79,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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 }} @@ -84,6 +91,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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_PROD }} diff --git a/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml b/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml index 02219ddc3d3..7c31d952d0f 100644 --- a/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml +++ b/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml @@ -48,6 +48,11 @@ jobs: sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example mv .env.example .env fi + 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/evaluation/eval-single-turn-metrics run: | @@ -74,6 +79,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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 }} @@ -84,6 +91,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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_PROD }} diff --git a/.github/workflows/samples_flows_standard_question_simulation.yml b/.github/workflows/samples_flows_standard_question_simulation.yml index 5a480be3a54..aa4217fc8e8 100644 --- a/.github/workflows/samples_flows_standard_question_simulation.yml +++ b/.github/workflows/samples_flows_standard_question_simulation.yml @@ -48,6 +48,11 @@ jobs: sed -i -e "s//$AOAI_API_KEY/g" -e "s//$AOAI_API_ENDPOINT/g" .env.example mv .env.example .env fi + 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/question-simulation run: | @@ -74,6 +79,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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 }} @@ -84,6 +91,8 @@ jobs: run: | export aoai_api_key=${{secrets.AOAI_API_KEY_TEST }} export aoai_api_endpoint=${{ secrets.AOAI_API_ENDPOINT_TEST }} + export AZURE_OPENAI_API_KEY=${{secrets.AOAI_API_KEY_TEST }} + export AZURE_OPENAI_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_PROD }} diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md index 078b57620d6..b3c274679ac 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.md @@ -11,7 +11,7 @@ This section contains a collection of flow samples and step-by-step tutorials. |CLI|[Working with connection](https://github.com/microsoft/promptflow/blob/main/examples/connections/README.md)| Manage various types of connections using cli |SDK|[Run prompt flow in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/get-started/quickstart-azure.ipynb)| A quick start tutorial to run a flow in Azure AI and evaluate it. |SDK|[Flow run management in Azure AI](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/run-management/cloud-run-management.ipynb)| Flow run management in azure AI -|SDK|[Develop promptflow copilot](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md)| A step by step guidance to develop a promptflow copilot. +|AZURE|[Develop promptflow copilot](https://github.com/microsoft/promptflow/blob/ce376aa6473774f93918e0a638c77c1151c82e29/examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md)| A step by step guidance to develop a promptflow copilot. ## Samples From 0d3e4a1638710d83c56a98bfe4bbaf4807b57952 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Wed, 8 May 2024 18:45:59 +0800 Subject: [PATCH 110/112] remove unnecessary require --- examples/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/requirements.txt b/examples/requirements.txt index 40b87fc4006..21832de3282 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -1,5 +1,4 @@ promptflow[azure] promptflow-tools -promptflow-vectordb python-dotenv bs4 From 32c7f65515b1653541e244980f2de775e2653694 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Thu, 9 May 2024 09:39:19 +0800 Subject: [PATCH 111/112] remove vectordb dependency from python node --- .../generate_prompt_context.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py index 1583a6a1edb..bf7d7cbf2d8 100644 --- a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py +++ b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py @@ -2,11 +2,9 @@ # Licensed under the MIT License. """File for context getting tool.""" from typing import List -from promptflow.core import tool -from promptflow_vectordb.core.contracts import SearchResultEntity +from promptflow import tool import re - @tool def generate_prompt_context(search_result: List[dict]) -> str: """Generate the context for the prompt.""" @@ -23,16 +21,17 @@ def format_doc(doc: dict): retrieved_docs = [] for item in search_result: - entity = SearchResultEntity.from_dict(item) - content = entity.text or "" + metadata = item.get("metadata", None) + content = item.get("text", "") source = "" - if entity.metadata is not None: - if SOURCE_KEY in entity.metadata: - if URL_KEY in entity.metadata[SOURCE_KEY]: - source = entity.metadata[SOURCE_KEY][URL_KEY] or "" + if metadata is not None: + if SOURCE_KEY in metadata: + if URL_KEY in metadata[SOURCE_KEY]: + source = metadata[SOURCE_KEY][URL_KEY] or "" + + source = re.sub(pattern, replacement_text, source) - source = re.sub(pattern, replacement_text, source) retrieved_docs.append({ "Content": content, "Source": source From 466cd0a659f347608922afa86df8be8a3d059f42 Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Thu, 9 May 2024 09:41:15 +0800 Subject: [PATCH 112/112] add black line --- .../flows/chat/promptflow-copilot/generate_prompt_context.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py index bf7d7cbf2d8..5ec741a7415 100644 --- a/examples/flows/chat/promptflow-copilot/generate_prompt_context.py +++ b/examples/flows/chat/promptflow-copilot/generate_prompt_context.py @@ -5,6 +5,7 @@ from promptflow import tool import re + @tool def generate_prompt_context(search_result: List[dict]) -> str: """Generate the context for the prompt."""

ePi}Le=Mbnoh3~_g>>Z#BUt2)o60u_UMfdBE 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 Date: Thu, 18 Jan 2024 15:10:09 +0800 Subject: [PATCH 013/112] update requirements txt and fix links --- docs/how-to-guides/construct-test-data.md | 6 +++--- examples/test_data_gen/test_data_gen_local/requirements.txt | 3 +++ .../test_data_gen/test_data_gen_pipeline/requirements.txt | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index c985fc611af..c8412cfc5eb 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -15,10 +15,10 @@ pip install -r requirements.txt ``` #### Get started -- Enter [construct_test_data_flow folder](examples\test_data_gen\construct_test_data_flow) to tune your prompt in order to customize your own test data gen logic. +- Enter [construct_test_data_flow folder](../../examples/test_data_gen/construct_test_data_flow/) to tune your prompt in order to customize your own test data gen logic. > [!Note] This step can be skipped if you just want to have a try. -- Enter [test_data_gen_local folder](examples\test_data_gen\test_data_gen_local) +- Enter [test_data_gen_local folder](../../examples/test_data_gen/test_data_gen_local) - Update configs in `configs.ini` - After configuration, run below command to gen test data set. ```bash @@ -35,7 +35,7 @@ pip install -r requirements.txt ``` #### Get started -- Enter [test_data_gen_pipeline folder](examples\test_data_gen\test_data_gen_pipeline) +- Enter [test_data_gen_pipeline folder](../../examples/test_data_gen/test_data_gen_pipeline) - Update configs in `configs.ini` - After configuration, run below command to gen test data set. ```bash diff --git a/examples/test_data_gen/test_data_gen_local/requirements.txt b/examples/test_data_gen/test_data_gen_local/requirements.txt index 8b0115aa698..0cda92a0b8b 100644 --- a/examples/test_data_gen/test_data_gen_local/requirements.txt +++ b/examples/test_data_gen/test_data_gen_local/requirements.txt @@ -1 +1,4 @@ +promptflow +promptflow-tools +llama_index configargparse diff --git a/examples/test_data_gen/test_data_gen_pipeline/requirements.txt b/examples/test_data_gen/test_data_gen_pipeline/requirements.txt index 251940c0794..2208d626dc1 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/requirements.txt +++ b/examples/test_data_gen/test_data_gen_pipeline/requirements.txt @@ -1,2 +1,5 @@ +promptflow +promptflow-tools configargparse +azure-ai-ml mldesigner From 63985728358eef4a830da04a9c59517d98076bd8 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Thu, 18 Jan 2024 16:21:49 +0800 Subject: [PATCH 014/112] refine generate context prompt --- .../generate_context_prompt.jinja2 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 index 9c21369c647..5c403ce6307 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 @@ -1,6 +1,13 @@ system: -Please extract relevant sentences from the provided context that can potentially help answer the following question. While extracting candidate sentences you're not allowed to make any changes to sentences from given context. +Please extract relevant sentences from the provided context that can potentially help answer the following question. +If no relevant sentence based on the given context to answer the following question, only return empty string without any other words. +While extracting candidate sentences you're not allowed to make any changes to sentences from given context. user: +question: What are the steps to tune prompts using variants? +context: Next steps +relevant sentences: + question:{{question}} -context:{{context}} \ No newline at end of file +context:{{context}} +relevant sentences: \ No newline at end of file From 444185c87555d952f7dce0ce2cb06954cf1f5c49 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Fri, 19 Jan 2024 09:00:04 +0800 Subject: [PATCH 015/112] update --- .../test_data_gen/document-nodes-test.jsonl | 303 +++++++++++++++++- .../test_data_gen_local/config.ini | 8 +- .../test_data_gen_pipeline/config.ini | 10 +- .../run_test_data_gen_pipeline.py | 29 +- 4 files changed, 324 insertions(+), 26 deletions(-) diff --git a/examples/test_data_gen/document-nodes-test.jsonl b/examples/test_data_gen/document-nodes-test.jsonl index 369ab79d650..40996506dfe 100644 --- a/examples/test_data_gen/document-nodes-test.jsonl +++ b/examples/test_data_gen/document-nodes-test.jsonl @@ -1,10 +1,293 @@ -{"document_node": "{\"id_\": \"caf64060-1332-4069-b458-23152b2f2093\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"41017365-74a3-41fc-ae0c-ecf997eb768a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"68b4e587d4fbc41b04e006b2a50568b747ac3c39e381ee3135d4c14245a7f75d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", \"text\": \"Connections\\n\\nConnections are for storing information about how to access external services like LLMs: endpoint, api keys etc.\\n\\n- In your local development environment, the connections are persisted in your local machine with keys encrypted.\\n- In Azure AI, connections can be configured to be shared across the entire workspace. Secrets associated with connections are securely persisted in the corresponding Azure Key Vault, adhering to robust security and compliance standards.\\n\\nPrompt flow provides a variety of pre-built connections, including Azure Open AI, Open AI, etc. These pre-built connections enable seamless integration with these resources within the built-in tools. Additionally, you have the flexibility to create custom connection types using key-value pairs, empowering them to tailor the connections to their specific requirements, particularly in Python tools.\\n\\n| Connection type | Built-in tools |\\n| ------------------------------------------------------------ | ------------------------------- |\\n| Azure Open AI | LLM or Python |\\n| Open AI | LLM or Python |\\n| Cognitive Search | Vector DB Lookup or Python |\\n| Serp | Serp API or Python |\\n| Custom | Python |\\n\\nBy leveraging connections in prompt flow, you can easily establish and manage connections to external APIs and data sources, facilitating efficient data exchange and interaction within their AI applications.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"db4c7302-af8a-4c76-b255-ebeebbf6ebf4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"49d146660c042ebfd906e88964b3e0e109718bd82cb5028b155b6eac23225567\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"caf64060-1332-4069-b458-23152b2f2093\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"text\": \"Next steps\\n\\n- Create connections\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c5c2ab6a-1010-480b-8698-f0a2cbd2affc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"45b587a27fffb03ba60fc08d97891b419752c6f33c425d6addadd88df084a58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"text\": \"Flows\\n\\nA flow in prompt flow is a DAG of functions (we call them tools). These functions/tools connected via input/output dependencies and executed based on the topology by prompt flow executor.\\n\\nA flow is represented as a YAML file and can be visualized with our Prompt flow for VS Code extension. Here is an example:\\n\\n!flow_dag\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b01685e-881f-475e-9ed4-b9bb42980041\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"57395fb0fcaa5f499bb9f4539ca4e9c71f76ae8ccad7f605fb7e6559cd12107a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"text\": \"Flow types\\n\\nPrompt flow has three flow types:\\n\\n- **Standard flow** and **Chat flow**: these two are for you to develop your LLM application. The primary difference between the two lies in the additional support provided by the \\\"Chat Flow\\\" for chat applications. For instance, you can define chat_history, chat_input, and chat_output for your flow. The prompt flow, in turn, will offer a chat-like experience (including conversation history) during the development of the flow. Moreover, it also provides a sample chat application for deployment purposes.\\n- **Evaluation flow** is for you to test/evaluate the quality of your LLM application (standard/chat flow). It usually run on the outputs of standard/chat flow, and compute some metrics that can be used to determine whether the standard/chat flow performs well. E.g. is the answer accurate? is the answer fact-based?\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c7ee995b-7278-4bc1-8351-0acea12bd8e0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"b1d47d4842372c06fa6f32e096456350fdd5cb9ea85026dd34cd72e8114ae9c9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"text\": \"When to use standard flow vs. chat flow?\\n\\nAs a general guideline, if you are building a chatbot that needs to maintain conversation history, try chat flow. In most other cases, standard flow should serve your needs.\\n\\nOur examples should also give you an idea when to use what:\\n- examples/flows/standard\\n- examples/flows/chat\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d2779b59-1578-4ae4-933c-4c3a6821bf35\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"3b0a9030ace8da8e4737290468dab2dbf390816d1bbac689514007ce41339e1e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"text\": \"Next steps\\n\\n- Quick start\\n- Initialize and test a flow\\n- Run and evaluate a flow\\n- Tune prompts using variants\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e371bf49-67a8-4b98-bcf2-12a77e25896c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"180b5669b22aa8a191ffad7db1be8bec23c03ce2d96af4fcce0e25234608b353\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"text\": \"Tools\\n\\nPrompt flow provides 3 basic tools:\\n- LLM: The LLM tool allows you to write custom prompts and leverage large language models to achieve specific goals, such as summarizing articles, generating customer support responses, and more.\\n- Python: The Python tool enables you to write custom Python functions to perform various tasks, such as fetching web pages, processing intermediate data, calling third-party APIs, and more.\\n- Prompt: The Prompt tool allows you to prepare a prompt as a string for more complex use cases or for use in conjunction with other prompt tools or python tools.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85765c00-82e9-437f-a117-9cdf60b63912\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"3dfe75d3b547f6773fc4b1e6f00d6d6f61fc935c809a6b2c1ba2c11cba9f6463\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"text\": \"More tools\\n\\nOur partners also contributes other useful tools for advanced scenarios, here are some links:\\n- Vector DB Lookup: vector search tool that allows users to search top k similar vectors from vector database.\\n- Faiss Index Lookup: querying within a user-provided Faiss-based vector store.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b43b95e3-8922-4ab3-8d7b-a68483744e36\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"70b917aabd4d8716f7449760089f5d8c9f6ab6087982d221edfc6634343a900f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"89acf666-f0a1-46eb-bd01-37132c001785\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"af92a6dde83927644357601cf0d5a2eb051f70052b0df437f0e38d7ca089d8f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"text\": \"Custom tools\\n\\nYou can create your own tools that can be shared with your team or anyone in the world. \\nLearn more on Create and Use Tool Package\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"document_node": "{\"id_\": \"89acf666-f0a1-46eb-bd01-37132c001785\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c255c14-bfe1-4fac-b228-e6d9b3feebf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"f4050ac206960c9b5b61a8af7547f6828c601115e1ef46fbfff321ed1114309e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e76c978-dbba-4dbd-b223-27d6a9f8bedb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-variants.md\", \"file_name\": \"concept-variants.md\", \"file_type\": null, \"file_size\": 2608, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a3d16a55ca08b91123b79ec62e83cdffdc2a691916ba7d365a95f2c2f10071ae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af92a6dde83927644357601cf0d5a2eb051f70052b0df437f0e38d7ca089d8f3\", \"text\": \"Next steps\\n\\nFor more information on the available tools and their usage, visit the our reference doc.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow.", "document_node": "{\"id_\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b402c5d-538d-408b-9cb1-d66d47fffa40\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a51a60cd4ae560e102258e62ad38f93648f1d46243cb797a66704c23cd9ab80a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"text\": \"Add conditional control to a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\\n\\nThis guide will help you learn how to use activate config to add conditional control to your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`.", "document_node": "{\"id_\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15868ad6-c777-44b2-8e97-9be423ee1483\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ad88a6a9078f088ce0a7ed654c73052d2178573eb746ac2c4162ef58f96634e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"text\": \"Prerequisites\\n\\nPlease ensure that your promptflow version is greater than `0.1.0b5`.\", \"start_char_idx\": 2, \"end_char_idx\": 86, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::", "document_node": "{\"id_\": \"31293458-8cee-4967-8348-4114666ad247\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"77279509-65c8-4fa1-9ced-eff19c2bd279\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"85d4f1ef1cd02a2a25836c3e629e10e19b777a402ee672b9021ae20a3cd5627d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"text\": \"Usage\\n\\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\\n\\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\\n\\n::::{tab-set}\\n:::{tab-item} YAML\\n:sync: YAML\\n\\nYou can add activate config in the node section of flow yaml.\\n```yaml\\nactivate:\\n when: ${node.output}\\n is: true\\n```\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\\n!visual_editor\\n\\n- Click on the `Activation config` section in the node you want to add and fill in the values for \\\"when\\\" and \\\"is\\\".\\n!activate_config\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1154, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed", "document_node": "{\"id_\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dd45d45-00c4-4909-a54a-4b03f741623a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b462c2a1e9f20e051210c996e39d721335d61d44c64a788cae8cb40292e9d443\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"text\": \"Further details and important notes\\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\\n\\n !provide_default_value\\n\\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\\n\\n !output_bypassed\\n\\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \\\"Bypassed\\\", as shown in the figure below Show. There are three situations in which a node is bypassed.\\n\\n !bypassed_nodes\\n\\n\\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\\n\\n !activate_condition_always_met\\n\\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\\n\\n !activate_when_bypassed\\n\\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\\n\\n !dependencies_bypassed\", \"start_char_idx\": 2, \"end_char_idx\": 1434, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example", "document_node": "{\"id_\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c3e1eb6-23bf-44d1-bda4-5d37c208ee12\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c2d44a764f3b69bd15d3a78bec6b1601edecc6dfbf80ae99d4a6572eec2b15e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"text\": \"Example flow\\n\\nLet's illustrate how to use activate config with practical examples.\\n\\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\\n- Switch scenario: Explore conditional flow for switch scenarios. View Example\", \"start_char_idx\": 2, \"end_char_idx\": 260, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\n- Run and evaluate a flow", "document_node": "{\"id_\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"782a7b53-7c3c-448c-8908-a78835c5561f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"80d3825fe6697eff08a6a2e7aec7eef79ea6fec62bcbb9e6d0013befe8c13811\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"text\": \"Next steps\\n\\n- Run and evaluate a flow\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to construct test data based on documents\nThis guide will help to construct test data based on the provided documents.\nThe test data construction process contains three steps:\n- Split documents to smaller trunks.\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\n- Collect all the test data and remove empty values.", "document_node": "{\"id_\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d762c45d-76f8-44b7-ad01-f762c3b68201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fedab640d7be99800a8d2565a8cb7ec2ab9a551623a2612ab024014c2a0c6269\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"text\": \"How to construct test data based on documents\\nThis guide will help to construct test data based on the provided documents.\\nThe test data construction process contains three steps:\\n- Split documents to smaller trunks.\\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\\n- Collect all the test data and remove empty values.\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data preprocess\nEnter `test_data_gen_local` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c3acac60-fcab-445a-a4e2-189036d3baea\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"875f62cb506a3703f747a728b452b208ee7384cc39c747e00d1a5155dbb0ccbf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"text\": \"Data preprocess\\nEnter `test_data_gen_local` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 145, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get started\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\n> [!Note] This step can be skipped if you just want to have a try.\n\n- Enter test_data_gen_local folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen.py\n ```\n - The generated test data would be a data jsonl file with path you configured in `config.ini`", "document_node": "{\"id_\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dfc13dfd-4b2e-4016-a57a-2d2306d8e5d4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b6ad8f04373fe87782c782471ea659a4fd0e338f74b248a7de9aded5eced04c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"text\": \"Get started\\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\\n> [!Note] This step can be skipped if you just want to have a try.\\n\\n- Enter test_data_gen_local folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen.py\\n ```\\n - The generated test data would be a data jsonl file with path you configured in `config.ini`\", \"start_char_idx\": 2, \"end_char_idx\": 489, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Cloud\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.", "document_node": "{\"id_\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e5582dc9-2527-4689-a66b-3499f60d39ec\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aab6ff042514dbdc1c619bf071e11425c08125c6f6f889eb0c78445e1ddf3b34\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"text\": \"Cloud\\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.\", \"start_char_idx\": 2, \"end_char_idx\": 95, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"880d9550-3b75-4405-b690-dac4ffff2d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ffa284d6ce0438755afec9d24989afc353c5ab2bdee44cfe9dfcfa9287fa312f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"text\": \"Prerequisites\\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 146, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get started\n- Enter test_data_gen_pipeline folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen_pipeline.py\n ```\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.", "document_node": "{\"id_\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"920d1a8d-54b7-495d-bba0-92c616963af6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff72434cf5652a1df86ae0d8e0a4d1cdb20755160a3b5b04c210cc3d180afe4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"text\": \"Get started\\n- Enter test_data_gen_pipeline folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen_pipeline.py\\n ```\\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash", "document_node": "{\"id_\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"985feda6-5910-4344-8ac2-8e1f004066b7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7566d96cdda7049299b58e66d25859f99137724b7dcaee863800e26459f95290\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"text\": \"Deploy a flow using development server\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nWe are going to use the web-classification as\\nan example to show how to deploy a flow.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \\nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \\nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \\nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \\n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \\nvalue as a fallback.\\n\\n\\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1340, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::", "document_node": "{\"id_\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4726d80-ea7e-4fba-9613-db83617bb882\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac3a543e1dceee101173b9bc7ff893ee9fb5a9ceae85efa8194cdc97b790151a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"text\": \"Serve the flow at localhost:8080\\npf flow serve --source --port 8080 --host localhost\\n```\\n\\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\\n\\n!img\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\nIn visual editor, choose:\\n!img\\nthen choose format:\\n!img\\nthen in yaml editor:\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 364, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::", "document_node": "{\"id_\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5920919b-f0f6-4e82-8f36-b0ed794adca7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3a597bc0d35a21864ac97adf0631fa8b80c3c91c6f9cfdbf2792054289656b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"text\": \"Test endpoint\\n::::{tab-set}\\n:::{tab-item} Bash\\nYou could open another terminal to test the endpoint with the following command:\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\\n:::\\n:::{tab-item} PowerShell\\nYou could open another terminal to test the endpoint with the following command:\\n```powershell\\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -Method POST -ContentType \\\"application/json\\\"\\n```\\n:::\\n:::{tab-item} Test Page\\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 778, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ebc2e916-88ef-49b3-95f7-c181df18e83a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45ffa4d534f92a3990305fa76c49e9bc990763b6a85a443546545b8853581739\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using docker.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image.", "document_node": "{\"id_\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"001a5af0-2cb9-4089-997c-197892a18fd7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3cb96282cb3a51734f72174afeb7eb4676623f5801355e4cc3bcf5bf4f520338\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"text\": \"Deploy a flow using Docker\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are two steps to deploy a flow using docker:\\n1. Build the flow as docker format.\\n2. Build and run the docker image.\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf2f3ae5-ba72-4beb-86a4-1bc49436e1da\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0057da34d9137e38191046124bf42bcf8c1c1f4a027da0f73bac07c083ee4554\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1ae36579-078a-4568-8aba-c5dda9d14b7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8c279a743b10f1167ab4728059c1d90e3b2b5415f812715b657fd620826065ad\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.", "document_node": "{\"id_\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dc49828-c68f-4468-9df7-b79c065f957e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a10de6a73f84be1c1b016021afada237667a01c4928fd4fe49dd16f6339cc2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"text\": \"Deploy with Docker\\nWe are going to use the web-classification as\\nan example to show how to deploy with docker.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\", \"start_char_idx\": 2, \"end_char_idx\": 244, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cf6e2bc6-78d1-49ec-a697-cb2842d6fe1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ab5f3b806ff2c792734f1c1ad6c7bb6e3568b15939996aaab1650926bd7113b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"text\": \"Build a flow as docker format app\\n\\nUse the command below to build a flow as docker format app:\\n\\n```bash\\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\\n```\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 283, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```", "document_node": "{\"id_\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"787280bc-ae47-42e9-b7bb-2cf6d722902f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"025c08762a5530fe9b4d08fc2ee90bd910c36f27c24c6b442a3396d375a4c9c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\\n\\nRun the command below to build image:\\n\\n```bash\\ndocker build dist -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container.", "document_node": "{\"id_\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24c4f02a-f692-45ae-b6db-af8952922b50\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305bc2ac535b78373a93bbec09010ac6f2e3a0c5eda71ea5520198308366bd88\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"text\": \"Run Docker image\\n\\nRun the docker image will start a service to serve the flow inside the container.\", \"start_char_idx\": 2, \"end_char_idx\": 101, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4d1cbd08-9a15-4dae-9977-1a5b3e0e96e3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"454d361baede9825a6b5a25526bb0659e713e58685077d7448585205f0b99fc2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash", "document_node": "{\"id_\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d4a6eb86-2f08-48ea-a19d-db7442b672a3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2a9c5bb24d9dc83e164398fda42138afca7298371035a2e2e6b5e79b9586e95\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"text\": \"Run with `docker run`\\n\\nYou can run the docker image directly set via below commands:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 94, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```", "document_node": "{\"id_\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4937a2c8-60fb-4b10-ad90-64e2e0ad9203\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5db95208bb6ad14c49e70ef284d9838cf1c03aec34a0529b167858504277263\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"text\": \"The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 196, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```", "document_node": "{\"id_\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"094daa74-2704-419b-88a3-d90b6b14be78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d5595bcd64f47bff9d713811f8ea973e1e144428cdeba4c28f2c6e35f373537d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"text\": \"Test the endpoint\\nAfter start the service, you can use curl to test it:\\n\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 249, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbb19bfc-117b-4108-b0f0-782008d0d6f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d32afb6a7a32f2d7209c5e9c81a494466c7b79c8aec3991f80e2c38b7c7ed429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment.", "document_node": "{\"id_\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35233e62-7f70-4f02-bcb0-266eb8bab18d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edb6e94975ce9597a7289e364191cb2f0d9ccc41c1dc29ed10078ed5bffe6201\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"text\": \"Deploy a flow using Kubernetes\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are four steps to deploy a flow using Kubernetes:\\n1. Build the flow as docker format.\\n2. Build the docker image.\\n3. Create Kubernetes deployment yaml.\\n4. Apply the deployment.\", \"start_char_idx\": 2, \"end_char_idx\": 329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash", "document_node": "{\"id_\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"03b68070-8b3a-4e97-b6b5-2efdbd897d0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c32dac478d5c6812b1c1b508fd58be363fd98dc2b93fa1629c5780685a5395ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote that all dependent connections must be created before building as docker.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 163, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9d0ff802-5f7e-4d38-9298-2fe1d72d162a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28da9c8ae14ba1d288700ff08b67f3c64af26e9c9260c5acbe9d3bfce4f0a81c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 490, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a465868-961b-42fa-aff4-023aec92284b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"737ada3363594778b97169c88d91adcd82c3852d6ad94c3afededb851566d7e9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.", "document_node": "{\"id_\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cd6a5ee9-be8a-4cd3-a609-588043b8a5dc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb90193d094243e3f362f8f4834d27aae9ae1cc9c64e9cb898666ef5efcd7a22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"text\": \"Deploy with Kubernetes\\nWe are going to use the web-classification as\\nan example to show how to deploy with Kubernetes.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.\", \"start_char_idx\": 2, \"end_char_idx\": 494, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```", "document_node": "{\"id_\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca057cce-ae41-4870-86c6-2a7e11df6884\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf0826466e0b7135f7fa8f52748ebd1e0bf36b6c9b70923142f15679305f1509\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\\n\\nThen run the command below:\\n\\n```bash\\ncd \\ndocker build . -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 266, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```", "document_node": "{\"id_\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"416b4a60-5b95-4610-8818-5c0a950e70b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39fd3d4d93952fc682966479183abf5b004eb51f53bc7a39a608b97d417fa280\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"text\": \"Create Kubernetes deployment yaml.\\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\\n\\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\\n```bash\\nencoded_secret=$(echo -n | base64)\\n```\\n\\n```yaml\\n---\\nkind: Namespace\\napiVersion: v1\\nmetadata:\\n name: \\n---\\napiVersion: v1\\nkind: Secret\\nmetadata:\\n name: open-ai-connection-api-key\\n namespace: \\ntype: Opaque\\ndata:\\n open-ai-connection-api-key: \\n---\\napiVersion: v1\\nkind: Service\\nmetadata:\\n name: web-classification-service\\n namespace: \\nspec:\\n type: NodePort\\n ports:\\n - name: http\\n port: 8080\\n targetPort: 8080\\n nodePort: 30123\\n selector:\\n app: web-classification-serve-app\\n---\\napiVersion: apps/v1\\nkind: Deployment\\nmetadata:\\n name: web-classification-serve-app\\n namespace: \\nspec:\\n selector:\\n matchLabels:\\n app: web-classification-serve-app\\n template:\\n metadata:\\n labels:\\n app: web-classification-serve-app\\n spec:\\n containers:\\n - name: web-classification-serve-container\\n image: \\n imagePullPolicy: Never\\n ports:\\n - containerPort: 8080\\n env:\\n - name: OPEN_AI_CONNECTION_API_KEY\\n valueFrom:\\n secretKeyRef:\\n name: open-ai-connection-api-key\\n key: open-ai-connection-api-key\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1691, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.", "document_node": "{\"id_\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2f87d0-7ce6-424f-baf5-9a719bd9e6dd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"477a540f66a6f1ee65bfd60768d2a3d59c1dcadacee96a857fe7f25753276d75\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"text\": \"Apply the deployment.\\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\\n```bash\\nminikube start\\n```\\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\\n```bash\\nkubectl apply -f deployment.yaml\\n```\\nThis command will create the necessary pods to run your application within the cluster.\\n\\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.\", \"start_char_idx\": 2, \"end_char_idx\": 697, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```", "document_node": "{\"id_\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e957261-66c9-478e-a059-e80a3e8b0978\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b6370003e6a7da8b9a3332e4ffb0c781dac39e5cfb2e2ceb896790c8a4128be4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"text\": \"Retrieve flow service logs of the container\\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\\n\\n```bash\\nkubectl -n logs \\n```\", \"start_char_idx\": 2, \"end_char_idx\": 281, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fc445c62-3acb-4049-8230-38c9d8466d0b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8215b76f0bcab42a64d833c86863fbdb33dcc95da1fb59674394281d6c6fa40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```", "document_node": "{\"id_\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"272125df-0bcb-4bd6-bf09-c0ec657b16e6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50a786047950de8aa8f76dfa723527bb5c7e34deb5595b227792230410c0f3c1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"text\": \"Test the endpoint\\n- Option1:\\n\\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\\n To achieve this, execute the following command:\\n\\n ```bash\\n kubectl port-forward : -n \\n ```\\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\\n\\n- Option2:\\n\\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\\n\\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \\n\\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1405, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.", "document_node": "{\"id_\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c90f24c2-70ef-4f4a-bec5-944c963c0017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f33e56b02f183c64dfe8e88bb3d10c17054eb93b672d3dfc9f7b81353b318734\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"text\": \"Next steps\\n- Try the example here.\", \"start_char_idx\": 2, \"end_char_idx\": 36, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.", "document_node": "{\"id_\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"78c930c3-0d07-47fa-bcb4-c05ee6801638\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce667521e60986a068e5688e6f7084f84281c241bc239aeacd088d8815f5d142\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"text\": \"Distribute flow as executable app\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nWe are going to use the web-classification as\\nan example to show how to distribute flow as executable app with Pyinstaller.\\n\\n\\nPlease ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \\n\\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.\", \"start_char_idx\": 2, \"end_char_idx\": 1262, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash", "document_node": "{\"id_\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"889137df-2303-4e28-9e25-af03a3dade9a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"788efa4a3e263596c0e89a318492f454d61b1947a3249b5817814acecccddf69\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"text\": \"Build a flow as executable format\\nNote that all dependent connections must be created before building as executable.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```", "document_node": "{\"id_\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b8cb107-8895-47b3-bb7b-4afda0994fcf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a5b966cba851cc99e639ac17d4e9ce03f6d8ec9b948b2b2ec507aa7e1a1fa00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as executable format:\\n```bash\\npf flow build --source --output --format executable\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 298, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files.", "document_node": "{\"id_\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cbcb9eaf-2132-477b-8703-ab3179413b0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60e4cbfdadc24044a4f6ff9eff16829666816426530e507bf35ac475af6e80ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"text\": \"Executable format folder structure\\n\\nExported files & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files.\\n- connections: the folder contains yaml files to create all related connections.\\n- app.py: the entry file is included as the entry point for the bundled application.\\n- app.spec: the spec file tells PyInstaller how to process your script.\\n- main.py: it will start streamlit service and be called by the entry file.\\n- settings.json: a json file to store the settings of the executable application.\\n- build: a folder contains various log and working files.\\n- dist: a folder contains the executable application.\\n- README.md: Simple introduction of the files.\", \"start_char_idx\": 2, \"end_char_idx\": 733, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```", "document_node": "{\"id_\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8754ca46-b358-442e-85aa-2dd01a1c60b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"525024450d56483fc20362c341d7af6062113e5f8fe6518a8b279a5c130d6ff3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"text\": \"A template script of the entry file\\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \\n\\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\\n\\n```python\\nimport os\\nimport sys\\n\\nfrom promptflow._cli._pf._connection import create_connection\\nfrom streamlit.web import cli as st_cli\\nfrom streamlit.runtime import exists\\n\\nfrom main import start\\n\\ndef is_yaml_file(file_path):\\n _, file_extension = os.path.splitext(file_path)\\n return file_extension.lower() in ('.yaml', '.yml')\\n\\ndef create_connections(directory_path) -> None:\\n for root, dirs, files in os.walk(directory_path):\\n for file in files:\\n file_path = os.path.join(root, file)\\n if is_yaml_file(file_path):\\n create_connection(file_path)\\n\\n\\nif __name__ == \\\"__main__\\\":\\n create_connections(os.path.join(os.path.dirname(__file__), \\\"connections\\\"))\\n if exists():\\n start()\\n else:\\n main_script = os.path.join(os.path.dirname(__file__), \\\"main.py\\\")\\n sys.argv = [\\\"streamlit\\\", \\\"run\\\", main_script, \\\"--global.developmentMode=false\\\"]\\n st_cli.main(prog_name=\\\"streamlit\\\")\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1486, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec", "document_node": "{\"id_\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35fb4943-f149-41fa-bdd4-d7e134bf38ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3359e5ab1140c765b2cec249fad745ee49bf26f68fb798200109fd048f8ea886\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"text\": \"A template script of the spec file\\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\\n\\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\\n\\n```spec\", \"start_char_idx\": 2, \"end_char_idx\": 626, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```", "document_node": "{\"id_\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e2b8a188-7744-48aa-bd3e-88622db05d16\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92c55ce053208bb4f5a6a40a6658a2620ec99440bbcb2e2984a892b3ab2b41ec\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"text\": \"-*- mode: python ; coding: utf-8 -*-\\nfrom PyInstaller.utils.hooks import collect_data_files\\nfrom PyInstaller.utils.hooks import copy_metadata\\n\\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\\ndatas += collect_data_files('streamlit')\\ndatas += copy_metadata('streamlit')\\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\\ndatas += copy_metadata('keyrings.alt')\\ndatas += collect_data_files('streamlit_quill')\\n\\nblock_cipher = None\\n\\n\\na = Analysis(\\n ['app.py', 'main.py'],\\n pathex=[],\\n binaries=[],\\n datas=datas,\\n hiddenimports=['bs4'],\\n hookspath=[],\\n hooksconfig={},\\n runtime_hooks=[],\\n excludes=[],\\n win_no_prefer_redirects=False,\\n win_private_assemblies=False,\\n cipher=block_cipher,\\n noarchive=False,\\n)\\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\\n\\nexe = EXE(\\n pyz,\\n a.scripts,\\n a.binaries,\\n a.zipfiles,\\n a.datas,\\n [],\\n name='app',\\n debug=False,\\n bootloader_ignore_signals=False,\\n strip=False,\\n upx=True,\\n upx_exclude=[],\\n runtime_tmpdir=None,\\n console=True,\\n disable_windowed_traceback=False,\\n argv_emulation=False,\\n target_arch=None,\\n codesign_identity=None,\\n entitlements_file=None,\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1331, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.", "document_node": "{\"id_\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbbf6b9c-6c93-4225-9464-811c74b323b1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"137b06713f5e2940b2fe428d41780bb47007f0e7ec4af0aae52c6ed2a843f992\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"text\": \"The bundled application using Pyinstaller\\nOnce you've build a flow as executable format following Build a flow as executable format.\\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```", "document_node": "{\"id_\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0dd26999-3784-4781-b921-16dc8238be64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554ae32ca1c480322848743e9c6da4fd7418108c6046d6cac9f2b84fba6edd71\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 501, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).", "document_node": "{\"id_\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c2d3b808-b23f-43eb-a47c-1222042cef68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9e38dad6f79b85483297a2e961c7074d5eb7b33e144a833dfeb034ffc8d6380\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"text\": \"Test the endpoint\\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \\n\\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\\n\\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\\n\\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).\", \"start_char_idx\": 2, \"end_char_idx\": 819, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.", "document_node": "{\"id_\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c33c3b24-6d2f-4008-886e-5f909d48d67f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c51e0c6b8fd6ab482b88267abb541c19a26e8a5ace41312d12b6934cfc961ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"text\": \"Known issues\\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.\", \"start_char_idx\": 2, \"end_char_idx\": 162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here", "document_node": "{\"id_\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a01c5abe-5e5a-4ddb-add2-e3860e52b7cc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e568ec67bd14372ad8610019228abfcab0577cf33fc2d5c498a88ba6889ba595\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"text\": \"Next steps\\n- Try the example here\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fedee87-d831-42e5-8868-b687b8669cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7fee890cde8a5e564cd8a0ac6f8e2e91acb42d8f07a7afb781d3e7fe3abad5de\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"text\": \"Develop chat flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 314, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"459ea5a0-07b2-4018-9d73-f5c12560a9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"34672e2e9b5d672a905e718c868c88a5dc1f874f92b883d54f30ea8c8bbc7251\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"text\": \"Flow input data\\n\\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\\n\\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\\n\\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\\n \\n An example of chat history:\\n ```python\\n [\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What types of container software there are?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"There are several types of container software available, including: Docker, Kubernetes\\\"}},\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What's the different between them?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\\\"}},\\n ] \\n ```\\n\\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\\n```yaml\\ninputs:\\n chat_history:\\n type: list\\n is_chat_history: true\\n default: []\\n question:\\n type: string\\n is_chat_input: true\\n default: What is ChatGPT?\\n```\\n\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 1811, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19e1d3da-0011-44c6-842e-f43872513fee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7174bd166b0fb96b0c3c56f110b7bf6b469e98368c15514bfc18c5bda0333ced\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow.", "document_node": "{\"id_\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec04b974-2730-40eb-b576-9ff5b98ec67a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f683434028ff51d70bcc3e19d09c958ea5fbac263b5b572a16e8cfcc6dfe623\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\\n\\nFor more information see chain your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```", "document_node": "{\"id_\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13f31c7e-48b2-4c8b-a22c-75a2ed4ef4a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09947add90687052194ef8af3b2f29e05eae203b6f2be62d68b64ed4e0c165e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"text\": \"Set flow output\\n\\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\\n\\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\\n\\n```yaml\\noutputs:\\n answer:\\n type: string\\n reference: ${chat.output}\\n is_chat_output: true\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 453, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.", "document_node": "{\"id_\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8155fe6d-e44d-4b32-a92d-cfd53d2d1dc9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"050307129fb74fe69bb453b44fb4578c009429623df62e027e90bd000d14aea4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"text\": \"Develop evaluation flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\\n\\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\\n- `Inputs/Outputs definition`\\n- `Nodes`\\n- `Chain nodes in a flow`\\n\\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.", "document_node": "{\"id_\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9af9790b-674a-4a32-b26d-76d74f80c201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30a482680af6d77ff4a32b07e7e70496af7d8e659d41e9ddd9bc1a3d2a9e799c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"text\": \"Evaluation flow example\\n\\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.\", \"start_char_idx\": 2, \"end_char_idx\": 439, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.", "document_node": "{\"id_\": \"f67eae57-2228-4768-bf9e-752182255315\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a928698-f22c-4012-85c2-e736a3205a32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"806a38502591403dda37598c10e796b0d0b5c7da92670db5caa94bd4059efa78\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"text\": \"Flow inputs\\n\\nThe flow `eval-classification-accuracy` contains two inputs:\\n\\n```yaml\\ninputs:\\n groundtruth:\\n type: string\\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\\n default: APP\\n prediction:\\n type: string\\n description: The actual predicted outputs that your flow produces.\\n default: APP\\n```\\n\\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \\n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\\n\\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1174, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.", "document_node": "{\"id_\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00b01149-18e5-4fb6-af7c-d1074b90fccb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de34c0d3cae520dc7074bb45e7e48909c31b019d26a7cb740829def7c0c2acdd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"text\": \"Aggregation node\\n\\n\\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\\n\\n```yaml\\n- name: grade\\n type: python\\n source:\\n type: code\\n path: grade.py\\n inputs:\\n groundtruth: ${inputs.groundtruth}\\n prediction: ${inputs.prediction}\\n```\\n\\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\\n\\n```python\\nfrom promptflow import tool\\n\\n@tool\\ndef grade(groundtruth: str, prediction: str):\\n return \\\"Correct\\\" if groundtruth.lower() == prediction.lower() else \\\"Incorrect\\\"\\n```\\n\\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\\n1. It has an attribute `aggregation` set to be `true`.\\n\\n```yaml\\n- name: calculate_accuracy\\n type: python\\n source:\\n type: code\\n path: calculate_accuracy.py\\n inputs:\\n grades: ${grade.output}\\n aggregation: true # Add this attribute to make it an aggregation node\\n```\\n\\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef calculate_accuracy(grades: List[str]):\\n result = []\\n for index in range(len(grades)):\\n grade = grades[index]\\n result.append(grade)\\n\\n # calculate accuracy for each variant\\n accuracy = round((result.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(\\\"accuracy\\\", accuracy)\\n\\n return result\\n```\\n\\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Channel\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\n\\n And we provides a data file like this:\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Channel\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nThen the `grades` value would be `[\\\"Correct\\\", \\\"Correct\\\", \\\"Incorrect\\\"]`, and the final accuracy is `0.67`. \\n\\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.\", \"start_char_idx\": 2, \"end_char_idx\": 2278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`.", "document_node": "{\"id_\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"952a2672-5398-4540-b942-4d7b4e729b92\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"822605742d13841acd10ffcea5db1d1a13e3e30e09dbb36b3e51a8d80046c79e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"text\": \"More about the list parameter\\n\\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\\n\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\\n\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nIn this case, the `grades` value would be `[\\\"Correct\\\", \\\"Incorrect\\\"]` and the accuracy is `0.5`.\", \"start_char_idx\": 2, \"end_char_idx\": 920, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img", "document_node": "{\"id_\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f7fa17f-8dee-470a-916d-e55d9fe11f1e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60ff341156316a69a77efdcace6fd85fa977b463e106c0110ba68ba78da5f0b5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"text\": \"How to set aggregation node in VS Code Extention\\n\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img", "document_node": "{\"id_\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a7d7d4cd-91ab-4d18-9812-73abab2aaac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62f9779b95c01ecabbbe5cdcda006b117a8dd30ff024f26bd9ec2d33ad4aa7f6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"text\": \"How to log metrics\\n:::{admonition} Limitation\\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\\n:::\\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \\n\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef example_log_metrics(grades: List[str]):\\n # this node is an aggregation node so it accepts a list of grades\\n metric_key = \\\"accuracy\\\"\\n metric_value = round((grades.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(metric_key, metric_value)\\n```\\n\\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 777, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"242a77a2-a306-40bf-93d7-cd6878f5b9bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97d57345e8b5efdb1c430e93e2262ab8995b9b9b3fbf17e9738b3decaf201c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"text\": \"Develop standard flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 322, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types.", "document_node": "{\"id_\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9635de74-544b-4e42-b80e-66f4a9558c00\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668b015e6c989c7d86e3dfcad898c06c44f445fe96bd6d6fccf909a044c1ede0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"text\": \"Flow input data\\nThe flow input data is the data that you want to process in your flow. \\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a flow input in inputs section of flow yaml.\\n```yaml\\ninputs:\\n url:\\n type: string\\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \\nand the input value.\\n\\n!flow_input\\n:::\\n\\n::::\\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\\nFor more input types in a python tool, please refer to Input types.\", \"start_char_idx\": 2, \"end_char_idx\": 757, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.", "document_node": "{\"id_\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"919ca595-35ff-4dba-8a31-26b416b7e3ab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0cf6fa20af96fe27dfaf6ee9484693e4513ea19ec3d3ef8e6b56ebcb0ecaea23\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\", \"start_char_idx\": 2, \"end_char_idx\": 212, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::", "document_node": "{\"id_\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c60c3d4-098c-4952-ba3b-0de0506f55f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0bcdc43c78e08ebcf9feadfbe7d897b9998f6b922626ed3c1870d182634403c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"text\": \"Add tool as your need\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\\n\\n!add_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool", "document_node": "{\"id_\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fdf5dd30-8270-4fee-aa1a-abcfbcbb512b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c3fadc7c5b72b98e4ba684a95f971986f4df0034a0a614271c2ffc78074df271\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"text\": \"Edit tool\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\\n\\n```python\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::", "document_node": "{\"id_\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b15324bb-86ed-44cb-bd91-796bc99a3242\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b2175984579bdcc522aadd3d3f03eac2d874f191c3230e9d5f99a7406f02ab54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"text\": \"The inputs section will change based on the arguments of the tool function, after you save the code\\n@tool\\ndef my_python_tool(input1: str) -> str:\\n return 'hello ' + input1\\n```\\n\\nWe also provide an LLM tool prompt below.\\n\\n```jinja\\nPlease summarize the following text in one paragraph. 100 words.\\nDo not add any information that is not in the text.\\nText: {{text}}\\nSummary:\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \\nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \\ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\\n!edit_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 938, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details.", "document_node": "{\"id_\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8372ff3d-7692-45b9-ac7d-81f0f40101b5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fdbc523c40c6af31143083203d50b7b08d2ea8520099eeda080947118eab3d00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"text\": \"Create connection\\nPlease refer to the Create necessary connections for details.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.", "document_node": "{\"id_\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01934a78-1481-496a-8449-4e8fe6e4a85f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"17c34f9a2db75c40a67d3f3bb44546b8ffe352ba6f837e324a7955cbf41877b2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\", \"start_char_idx\": 2, \"end_char_idx\": 114, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```", "document_node": "{\"id_\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86c4ea6f-359c-484e-b68e-431c7adcf5c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45184bbd7413f02695ec0459bc753bb0bc538058b5e19dc48636c3bb7e15f50c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"text\": \"Define LLM node interface\\nLLM node has only one output, the completion given by LLM provider.\\n\\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \\nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \\ntemplating language. For example:\\n\\n```jinja\\nYour task is to classify a given url into one of the following types:\\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\\nThe classification will be based on the url, the webpage text content summary, or both.\\n\\nHere are a few examples:\\n{% for ex in examples %}\\nURL: {{ex.url}}\\nText content: {{ex.text_content}}\\nOUTPUT:\\n{\\\"category\\\": \\\"{{ex.category}}\\\", \\\"evidence\\\": \\\"{{ex.evidence}}\\\"}\\n\\n{% endfor %}\\n\\nFor a given URL : {{url}}, and text content: {{text_content}}.\\nClassify above url to complete the category and indicate evidence.\\nOUTPUT:\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 958, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```", "document_node": "{\"id_\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0d6a1e23-9c61-456e-b5f8-6646774e7517\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7098a85fc27d133c1dd382abf3c7c82f3704b115745129d0b4c63e59891bbcb6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"text\": \"Define Python node interface\\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \\nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\\nFor example:\\n\\n```python\\nimport json\\nfrom promptflow import tool\\n\\n@tool\\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\\n try:\\n print(input_str2)\\n return json.loads(input_str)\\n except Exception as e:\\n print(\\\"input is not valid, error: {}\\\".format(e))\\n return {\\\"category\\\": \\\"None\\\", \\\"evidence\\\": \\\"None\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 595, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together.", "document_node": "{\"id_\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2b337a61-282c-4aa0-8cc2-a303344a3a87\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"72154d54360f4b5a82884b63734ac5365a69ed681123ba1e32eb8718628ee58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"text\": \"Link nodes together\\nAfter the interface is defined, you can use:\\n\\n- ${inputs.key} to link with flow input.\\n- ${upstream_node_name.output} to link with single-output upstream node.\\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\\n\\nBelow are common scenarios for linking nodes together.\", \"start_char_idx\": 2, \"end_char_idx\": 313, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.", "document_node": "{\"id_\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c06825b-2eca-437e-81ef-b400683e5107\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dc503dd0dd29d203ef8868753fef7c97754d409dead2aab234f87acf6388f82b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"text\": \"Scenario 1 - Link LLM node with flow input and single-output upstream node\\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \\nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link the LLM node input with flow input by `${inputs.url}`. \\nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \\nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n url: ${inputs.url} # Link with flow input\\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \\nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \\n\\n!link_llm_with_flow_input_single_output_node\\n:::\\n\\n::::\\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \\n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1746, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.", "document_node": "{\"id_\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57a1605b-80c4-4052-8504-33374b92caee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8cf98f614b216b0d506c5cbbb9581ef3ca68bad51e3877c4935b7ef16ecb6e4c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"text\": \"Scenario 2 - Link LLM node with multi-output upstream node\\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \\nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\\n\\n!link_llm_with_multi_output_node\\n:::\\n::::\\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1273, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.", "document_node": "{\"id_\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8126884c-df49-43ba-9d3f-1a9638cd235d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a42c7be5b7c364c1f60b09c4d2756084cd1c9d628ef3fad2380f9b736ce02b20\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"text\": \"Scenario 3 - Link Python node with upstream node/flow input\\nAfter you add a new Python node and edit the code file like Define Python node interface], \\ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \\nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n```yaml\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs:\\n input_str: ${inputs.url} # Link Python node with flow input\\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n!link_python_with_flow_node_input\\n:::\\n\\n::::\\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \\ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1045, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::", "document_node": "{\"id_\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c8228df-9c72-4af5-b9c4-7369ed0f78e8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"35e2f7644a2153debed83c13170ff3cc72a2a0396587f4c47bebb3e814c9c005\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"text\": \"Set flow output\\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \\nmultiple nodes in one place. Moreover, flow output helps:\\n\\n- Check bulk test results in one single table.\\n- Define evaluation interface mapping.\\n- Set deployment response schema.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \\nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \\n`convert_to_dict`.\\n\\n```yaml\\noutputs:\\n category:\\n type: string\\n reference: ${convert_to_dict.output.category}\\n evidence:\\n type: string\\n reference: ${convert_to_dict.output.evidence}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \\nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \\n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\\n\\n!flow_output\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1194, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.", "document_node": "{\"id_\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"66907d7f-5f3f-48c2-9669-2c366a8ae143\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"75e4c5eee350016added3ec9fe497df916fbd71d627b305a3190eb538cc362a4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"text\": \"Referencing external files/folders in a flow\\n\\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\\n\\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/classify_with_llm.jinja2\\n- ../web-classification/convert_to_dict.py\\n- ../web-classification/fetch_text_content_from_url.py\\n- ../web-classification/prepare_examples.py\\n- ../web-classification/summarize_text_content.jinja2\\n- ../web-classification/summarize_text_content__variant_1.jinja2\\n```\\n\\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\\n\\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n```\\n\\nThe entry file \\\"fetch_text_content_from_url.py\\\" of the tool node \\\"fetch_text_content_from_url\\\" is located in \\\"../web-classification/fetch_text_content_from_url.py\\\", as specified in the additional_includes field. The same applies to the \\\"summarize_text_content\\\" tool nodes.\\n\\n> **Note**:\\n>\\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\\nTake the following YAML structure as an example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/prepare_examples.py\\n- ../tmp/prepare_examples.py\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n``` \\n\\nIn this case, the system will use \\\"../tmp/prepare_examples.py\\\" as the entry file for the tool node \\\"prepare_examples\\\". Even if there is a file named \\\"prepare_examples.py\\\" in the flow folder, the system will still use the file \\\"../tmp/prepare_examples.py\\\" specified in the `additional_includes` field.\\n\\n> Tips:\\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.\", \"start_char_idx\": 2, \"end_char_idx\": 3451, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.", "document_node": "{\"id_\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2b7611-b6e8-41d5-bcb7-857e344fb92a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"14430280f768c113dbf9e583b57be7eb327a7edbaf80889e72c017b668b89311\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"text\": \"Adding a tool icon\\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\\n\\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.\", \"start_char_idx\": 2, \"end_char_idx\": 295, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference.", "document_node": "{\"id_\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57058ab8-fa89-4e8a-a86f-8f8f6d8843bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb4c72a52e728f4c06cb906c2535c4d2d1e3e2b9c9ccf274d6c6fa6a2257c4c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"text\": \"Prerequisites\\n\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\\n- Create a tool package as described in Create and Use Tool Package.\\n- Prepare custom icon image that meets these requirements:\\n\\n - Use PNG, JPG or BMP format.\\n - 16x16 pixels to prevent distortion when resizing.\\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \\n\\n See this example as a reference.\", \"start_char_idx\": 2, \"end_char_idx\": 526, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Add tool icon with _icon_ parameter", "document_node": "{\"id_\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5b08ae97-5546-4d8a-8170-1e00ceabc742\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"200723951d139ca9f747a814fe55f43bf4c437d9ca9165060bd9ec9962224d93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"text\": \"Add tool icon with _icon_ parameter\", \"start_char_idx\": 2, \"end_char_idx\": 37, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```", "document_node": "{\"id_\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"04cb4765-6550-47b7-9cee-1ae8b0d9dfef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bfa267daed05b823404227af4ca8eaabad2e04b3069149430390fe220d5df245\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"text\": \"Initialize a package tool with icon\\nYou can use pf tool init to initialize a package tool with icon:\\n```bash\\npf tool init --package --tool --set icon=\\n```\\n\\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\\n```python\\nfrom pathlib import Path\\n\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n icon=Path(__file__).parent.parent / \\\"icons\\\" / \\\"custom-tool-icon.png\\\"\\n)\\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\\n\\nThe folder structure of the generated tool package is as follows:\\n```\\n\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u251c\\u2500\\u2500\\u2500icons\\n\\u2502 \\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500\\n .py\\n utils.py\\n __init__.py\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1222, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension", "document_node": "{\"id_\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a6b4670f-1911-41c2-816e-2afb835bce01\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1abe48bedddbcc1787d670a0952e7a3a82f2de7afce76d2d985ec9d05645a0cd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"text\": \"Verify the tool icon in VS Code extension\\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \\n!custom-tool-with-icon-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 176, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```", "document_node": "{\"id_\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9538f81c-1db6-4c2a-bbb5-ef36ca94fe44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbae9925b9e8426daba0ea2c01d494ed28a0e6dfd7437106812478371a299361\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"text\": \"FAQ\\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\\n```\\npython \\\\tool\\\\convert_image_to_data_url.py --image-path -o \\n```\\nFor example:\\n```\\npython D:\\\\proj\\\\github\\\\promptflow\\\\scripts\\\\tool\\\\convert_image_to_data_url.py --image-path D:\\\\proj\\\\github\\\\promptflow\\\\examples\\\\tools\\\\tool-package-quickstart\\\\my_tool_package\\\\icons\\\\custom-tool-icon.png -o output.html\\n```\\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\\n```html\\n\\n\\n\\n\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 580, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```", "document_node": "{\"id_\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"699ce5b2-187c-46f3-9f9c-b3b535acd91c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d707888b7220646c246f2b7886f82a2e315b193744d4f9c407ffd60a44e1c6a3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"text\": \"Can I add a tool icon to an existing tool package\\n\\nYou can follow these steps to add an icon to an existing package tool:\\n1. Copy the icon image to the package folder.\\n2. Configure the icon for the tool.\\n\\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\\n ```python\\n from promptflow import tool\\n\\n @tool(name=\\\"tool_name\\\", icon=)\\n def tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n ```\\n3. Update `MANIFEST.in` in the package folder.\\n\\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\\n ```\\n include \\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 769, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.", "document_node": "{\"id_\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca4ccdf3-090d-45f9-9d6a-07979afc72ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3d4af681b648feaf107b311553825afe2354879d3aec8e50615a0ed039d2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"text\": \"Can I add tool icons for dark and light mode separately?\\nYes, you can add the tool icon data to the tool code as follows:\\n```python\\nfrom promptflow import tool\\n\\n@tool(name=\\\"tool_name\\\", icon_dark=, icon_light=)\\ndef tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n```\\n\\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\\n```python\\npf tool init --tool --set icon_dark= icon_light=\\n```\\n\\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.\", \"start_char_idx\": 2, \"end_char_idx\": 756, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field.", "document_node": "{\"id_\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01518a9e-e18d-4949-9626-094903eea51c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be5cd30b0f09f966dbb2e5f5edbbbd36d25301c73f444f5f31f9585dba4c0c81\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"text\": \"Adding category and tags for tool\\n\\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\\n\\n| Attribute | Type | Required | Description |\\n| --------- | ---- | -------- | ----------- |\\n| category | str | No | Organizes tools into folders by common features. |\\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\\n\\n**Important Notes:**\\n- Tools without an assigned category will be listed in the root folder.\\n- Tools lacking tags will display an empty tags field.\", \"start_char_idx\": 2, \"end_char_idx\": 1063, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.", "document_node": "{\"id_\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8779355d-d614-4b16-835d-d0721a33dc45\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74313f42ccdbca8b27db5e01299294ae7b0bf1a6ec47b19245225df77fa5f403\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 186, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```", "document_node": "{\"id_\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8d6db4b6-5a82-49d7-ac61-f26dfe211484\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8444fd90e8cf147e712f4a38ad588c732d2520d4f678a8b1455c1853ec50da8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"text\": \"How to add category and tags for a tool\\n\\nYou can use pf tool init to initialize a package tool with category and tags:\\n```python\\npf tool init --package --tool --set category= tags=\\n\\n```\\n\\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\\n```python\\npf tool init --tool my_tool --set name=\\\"My First Tool\\\" description=\\\"This is my first tool\\\" category=\\\"test_tool\\\" tags=\\\"{'tag1':'value1','tag2':'value2'}\\\"\\n```\\nThe generated tool script is as follows, where category and tags have been configured on the tool:\\n```python\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n category=\\\"test_tool\\\",\\n tags={\\\"tag1\\\": \\\"value1\\\", \\\"tag2\\\": \\\"value2\\\"},\\n)\\ndef my_tool(self, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1189, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag", "document_node": "{\"id_\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddf33403-cee1-4e76-a2ab-f6ec20ab5391\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce8dfca466c3c5f8a3b0f25cefa6575a14aac45fc4c6bd71b81025b60a999429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"text\": \"Tool with category and tags experience in VS Code extension\\nFollow the steps to use your tool via the VS Code extension.\\n- Experience in the tool tree\\n!category_and_tags_in_tool_tree\\n\\n- Experience in the tool list\\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\\n!category_and_tags_in_tool_list\\nFurthermore, you have the option to search or filter tools based on tags:\\n!filter_tools_by_tag\", \"start_char_idx\": 2, \"end_char_idx\": 443, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```", "document_node": "{\"id_\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"344346f5-1b0d-44f2-9731-80d27521e130\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4efeae08cd9f495b68b9d5c9738dbcf9caa03eae09cf94a5fc1567bd33f706d5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"text\": \"FAQ\\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\\n```python\\n@tool(\\n name=\\\"tool_name\\\",\\n description=\\\"This is tool_name tool\\\",\\n category=,\\n tags=,\\n)\\ndef tool_name(input_text: str) -> str:\\n # tool logic\\n pass\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 285, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list", "document_node": "{\"id_\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8eb7c175-5eb4-4be1-904f-f815a877641c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"761b3c022375969240ebb1501804424057266c488c43981e362d1b0a23a21831\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"text\": \"Create and use tool package\\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\\n\\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\\n\\nAfter successful installation of the package, your custom \\\"tool\\\" will show up in VSCode extension as below: \\n!custom-tool-list\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.", "document_node": "{\"id_\": \"936062d7-da6f-425e-8071-eec693938da0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4e9a3b-17ed-41b4-af95-541b9285769d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6d0592c1fbf449100098a1897232c851f0023246794d1404df65486e26b30ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"text\": \"Create your own tool package\\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.\", \"start_char_idx\": 2, \"end_char_idx\": 150, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```", "document_node": "{\"id_\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02d44090-c629-4857-8fb8-f857f9743f31\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c283b0aa603e66d9c0593d1f97704896afe43f3c0562e30fdd8b1490164d4b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"text\": \"Prerequisites\\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\\n```\\npip install promptflow\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure.", "document_node": "{\"id_\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cb076bf-bda4-491f-b36b-90646bf39825\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4d88291fa44db81f7df84aa930a343b8e56aa76fbd22cd6831525a828d2bdb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"text\": \"Create custom tool package\\nYou can use pf tool init to initialize a package tool in current folder:\\n\\n```bash\\npf tool init --package --tool \\n\\n```\\nFor example:\\n```bash\\npf tool init --package hello_world --tool hello_world_tool\\n```\\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\\n\\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\\n\\n```\\nhello_world/\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500hello_world/\\n hello_world_tool.py\\n utils.py\\n __init__.py\\n```\\n\\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\\n\\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \\n\\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\\n ```python\\n entry_points={\\n \\\"package_tools\\\": [\\\" = :\\\"],\\n },\\n ```\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\", \"start_char_idx\": 2, \"end_char_idx\": 3024, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.", "document_node": "{\"id_\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb45998c-8b7b-47c6-8563-3cc43e460689\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e56c43e15838921293454392a9f5431b91b0d337bc691b653cef4250b6d5e52b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"text\": \"Build and share the tool package\\n Execute the following command in the tool package root directory to build your tool package:\\n ```\\n python setup.py sdist bdist_wheel\\n ```\\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\\n\\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\\n\\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\\n\\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.\", \"start_char_idx\": 2, \"end_char_idx\": 1081, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension", "document_node": "{\"id_\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a2aac4b6-dee0-40c8-b78f-fa6c85823c0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6dac8b1537a6e23487b63d97bffeeda30df26f43280d740357e8e84c36c3081a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"text\": \"Use your tool from VSCode Extension\\n* Step1: Install Prompt flow for VS Code extension. \\n\\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\\n ```\\n (local_test) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> conda activate prompt-flow\\n (prompt-flow) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> pip install .\\\\dist\\\\my_tools_package-0.0.1-py3-none-any.whl\\n ``` \\n\\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\\n!auto-list-tool-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 745, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.", "document_node": "{\"id_\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25ceaf4b-d75c-452e-b038-cb1cff034017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a67937099d4ff70a170e33ffc30f7d928d2833bfa58a1bbe333e21e7507e09e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"text\": \"FAQs\\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\\n\\n 1. Make sure to install the tool package in your conda environment before executing this script.\\n 2. Create a python file anywhere and copy the content below into it.\\n ```python\\n import importlib\\n import importlib.metadata\\n\\n def test():\\n \\\"\\\"\\\"List all package tools information using the `package-tools` entry point.\\n\\n This function iterates through all entry points registered under the group \\\"package_tools.\\\"\\n For each tool, it imports the associated module to ensure its validity and then prints\\n information about the tool.\\n\\n Note:\\n - Make sure your package is correctly packed to appear in the list.\\n - The module is imported to validate its presence and correctness.\\n\\n Example of tool information printed:\\n ----identifier\\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\\n \\\"\\\"\\\"\\n entry_points = importlib.metadata.entry_points()\\n PACKAGE_TOOLS_ENTRY = \\\"package_tools\\\"\\n if isinstance(entry_points, list):\\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\\n else:\\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\\n for entry_point in entry_points:\\n list_tool_func = entry_point.load()\\n package_tools = list_tool_func()\\n\\n for identifier, tool in package_tools.items():\\n importlib.import_module(tool[\\\"module\\\"]) # Import the module to ensure its validity\\n print(f\\\"----{identifier}\\\\n{tool}\\\")\\n\\n if __name__ == \\\"__main__\\\":\\n test()\\n ```\\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.\", \"start_char_idx\": 2, \"end_char_idx\": 2062, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.", "document_node": "{\"id_\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"361d2447-b4f8-4f35-a1af-8892d249e13a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"55e3663e73f77321999c9beef546505b42179a322bae4b28bb738f35af78f7c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"text\": \"Why am I unable to upload package to PyPI?\\n* Make sure that the entered username and password of your PyPI account are accurate.\\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.\", \"start_char_idx\": 2, \"end_char_idx\": 654, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs", "document_node": "{\"id_\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4c66da-b14f-452c-9927-49b39d9cd181\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8d7ea9fb7c1ff5d72950bbb6b92aa6aafe99722a29b7723c16ec2fae992a4d83\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"text\": \"Advanced features\\n- Add a Tool Icon \\n- Add Category and Tags for Tool \\n- Create and Use Your Own Custom Strong Type Connection \\n- Customize an LLM Tool \\n- Use File Path as Tool Input \\n- Create a Dynamic List Tool Input \\n- Create Cascading Tool Inputs\", \"start_char_idx\": 2, \"end_char_idx\": 258, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.", "document_node": "{\"id_\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f82dbbc6-86b4-4928-8eec-c50b955110f6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbfca4e40603faa2d69519faaf0e6a2bee1c43b0f5f9d625ef9172cf40e2d822\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"text\": \"Creating cascading tool inputs\\n\\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.\", \"start_char_idx\": 2, \"end_char_idx\": 303, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6da446b1-c160-474d-89f3-f9f3659daaa0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f552409c79c5e4003de24d7f1a2f627a4005d8711975f42568830bb585d7fc54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"text\": \"Prerequisites\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 237, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```", "document_node": "{\"id_\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5fbd0902-ccbb-4e1e-b205-f191c87d3f39\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fae50d17a2ec06631c825bbd2772d5c2952857c4632a2670168971f1401afe09\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"text\": \"Create a tool with cascading inputs\\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\\n\\nDevelop the tool function, following the cascading inputs example. Key points:\\n * Use the `@tool` decorator to mark the function as a tool.\\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\\n * Conditionally use inputs in the tool logic based on `user_type`.\\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\\n\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass UserType(str, Enum):\\n STUDENT = \\\"student\\\"\\n TEACHER = \\\"teacher\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Enabled By Value\\\",\\n description=\\\"This is my tool with enabled by value\\\",\\n input_settings={\\n \\\"teacher_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.TEACHER]),\\n \\\"student_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.STUDENT]),\\n }\\n)\\ndef my_tool(user_type: UserType, student_id: str = \\\"\\\", teacher_id: str = \\\"\\\") -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\n :param user_type: user type, student or teacher.\\n :param student_id: student id.\\n :param teacher_id: teacher id.\\n :return: id of the user.\\n If user_type is student, return student_id.\\n If user_type is teacher, return teacher_id.\\n \\\"\\\"\\\"\\n if user_type == UserType.STUDENT:\\n return student_id\\n elif user_type == UserType.TEACHER:\\n return teacher_id\\n else:\\n raise Exception(\\\"Invalid user.\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png", "document_node": "{\"id_\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95ee1c93-3fd8-4ccf-8c4c-76c63f5e6d68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"04fcb935e815a4801293eb7a2cf3895cc849cac7965b173b1c94fff6e473857e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"text\": \"Use the tool in VS Code\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\\n\\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\\n!before_user_type_selected.png\\n!after_user_type_selected_with_student.png\\n!after_user_type_selected_with_teacher.png\", \"start_char_idx\": 2, \"end_char_idx\": 417, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections.", "document_node": "{\"id_\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d27b2b3a-1f85-4708-b438-61936edefd56\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4cc9eeedc959aaa970d6346b761f25e5ade25ff26ab512556114ab76bebacf51\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"text\": \"FAQs\\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass EventType(str, Enum):\\n CORPORATE = \\\"corporate\\\"\\n PRIVATE = \\\"private\\\"\\n\\n\\nclass CorporateTheme(str, Enum):\\n SEMINAR = \\\"seminar\\\"\\n TEAM_BUILDING = \\\"team_building\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Multi-Layer Cascading Inputs\\\",\\n description=\\\"This is my tool with multi-layer cascading inputs\\\",\\n input_settings={\\n \\\"corporate_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[EventType.CORPORATE]),\\n \\\"seminar_location\\\": InputSetting(enabled_by=\\\"corporate_theme\\\", enabled_by_value=[CorporateTheme.SEMINAR]),\\n \\\"private_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[CorporateTheme.PRIVATE]),\\n }\\n)\\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\\"\\\"\\\"\\n pass\\n```\\nInputs will be enabled in a cascading way based on selections.\", \"start_char_idx\": 2, \"end_char_idx\": 1231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.", "document_node": "{\"id_\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67f40a0f-b078-4cc6-ab1e-949e061951a4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"253f1ef689b236779c4139c7b8a8596611a636413e760e9e65f92f24ba76df17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"text\": \"Creating a dynamic list tool input\\n\\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.\", \"start_char_idx\": 2, \"end_char_idx\": 507, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a289ce7d-3868-4476-b3c7-b04b6fffff8f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a62c53dbbe33681ff3ce43af54ec4c0c19328db473d060fb7b1f03598cffe84\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"text\": \"Prerequisites\\n\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 238, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a tool input with dynamic listing", "document_node": "{\"id_\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3cebe967-3b58-4f05-9acc-4b816ed796f9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1936ac053e77c95327c1bc7149e8bce2b7e1f7daf68aacac3294d6b850521487\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"text\": \"Create a tool input with dynamic listing\", \"start_char_idx\": 2, \"end_char_idx\": 42, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```", "document_node": "{\"id_\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e969bbff-b1eb-4490-b321-c72e7e471292\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbf6f556b19f8044dccf35bc5441bc853d43b758c6b30151e64513903af9ff2f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"text\": \"Create a list function\\n\\nTo enable dynamic listing, the tool author defines a request function with the following structure:\\n\\n- Type: Regular Python function, can be in tool file or separate file\\n- Input: Accepts parameters needed to fetch options\\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\\n - Required key:\\n - `value`: Internal option value passed to tool function\\n - Optional keys:\\n - `display_value`: Display text shown in dropdown (defaults to `value`)\\n - `hyperlink`: URL to open when option clicked\\n - `description`: Tooltip text on hover\\n\\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\\n\\n```python\\ndef my_list_func(prefix: str = \\\"\\\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\\n \\\"\\\"\\\"This is a dummy function to generate a list of items.\\n\\n :param prefix: prefix to add to each item.\\n :param size: number of items to generate.\\n :param kwargs: other parameters.\\n :return: a list of items. Each item is a dict with the following keys:\\n - value: for backend use. Required.\\n - display_value: for UI display. Optional.\\n - hyperlink: external link. Optional.\\n - description: information icon tip. Optional.\\n \\\"\\\"\\\"\\n import random\\n\\n words = [\\\"apple\\\", \\\"banana\\\", \\\"cherry\\\", \\\"date\\\", \\\"elderberry\\\", \\\"fig\\\", \\\"grape\\\", \\\"honeydew\\\", \\\"kiwi\\\", \\\"lemon\\\"]\\n result = []\\n for i in range(size):\\n random_word = f\\\"{random.choice(words)}{i}\\\"\\n cur_item = {\\n \\\"value\\\": random_word,\\n \\\"display_value\\\": f\\\"{prefix}_{random_word}\\\",\\n \\\"hyperlink\\\": f'https://www.bing.com/search?q={random_word}',\\n \\\"description\\\": f\\\"this is {i} item\\\",\\n }\\n result.append(cur_item)\\n\\n return result\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2026, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```", "document_node": "{\"id_\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0939118b-828a-4de3-98e9-776c2b8037ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"94f5070b41fbce81858222caf99a4153bd8580851d8f0acf8efaca5417fac9b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"text\": \"Configure a tool input with the list function\\n\\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\\n\\n- `DynamicList`:\\n - `function`: Path to the list function (module_name.function_name).\\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\\n- `is_multi_select`: Allow user to select multiple values. Default to false.\\n\\nSee tool_with_dynamic_list_input.py as an example.\\n\\n```python\\nfrom promptflow._core.tool import tool\\nfrom promptflow.entities import InputSetting, DynamicList\\n\\n\\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\\\"prefix\\\": \\\"input_prefix\\\"})\\ninput_settings = {\\n \\\"input_text\\\": InputSetting(\\n dynamic_list=dynamic_list_setting,\\n allow_manual_entry=True,\\n is_multi_select=True\\n )\\n}\\n\\n\\n@tool(\\n name=\\\"My Tool with Dynamic List Input\\\",\\n description=\\\"This is my tool with dynamic list input\\\",\\n input_settings=input_settings\\n)\\ndef my_tool(input_text: list, input_prefix: str) -> str:\\n return f\\\"Hello {input_prefix} {','.join(input_text)}\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1188, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.", "document_node": "{\"id_\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"241031e5-137a-4f62-8578-f9ae17176b94\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a22fc60300c108cc9ab2a273d80eab0db119f7e244396d4b27e13ac238703bf4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"text\": \"Use the tool in VS Code\\n\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\\n\\n```sh\\npip install my-tools-package>=0.0.8\\n```\\n\\n!dynamic list tool input options\\n!dynamic list tool input selected\\n\\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs", "document_node": "{\"id_\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52cf13ef-f7c7-4777-826e-3436e6fa10a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f155f38296df1d151acb9003db8e8b02ab7afa2138997d07168a8b16c93ecef3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure", "document_node": "{\"id_\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2670701d-65c8-4d71-93bf-9dc1af4ebd73\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e363a58b67cb6b64c1d4d39e722c563b324dcd45713d1ea775f43d875d420f54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"text\": \"I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\\n1. Clarify azure workspace triple \\\"subscription_id\\\", \\\"resource_group_name\\\", \\\"workspace_name\\\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\\n```python\\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \\\"\\\") -> List[Dict[str, str]]:\\n \\\"\\\"\\\"This is an example to show how to get Azure ML resource in tool input list function.\\n\\n :param subscription_id: Azure subscription id.\\n :param resource_group_name: Azure resource group name.\\n :param workspace_name: Azure ML workspace name.\\n :param prefix: prefix to add to each item.\\n \\\"\\\"\\\"\\n from azure.ai.ml import MLClient\\n from azure.identity import DefaultAzureCredential\\n\\n credential = DefaultAzureCredential()\\n credential.get_token(\\\"https://management.azure.com/.default\\\")\\n\\n ml_client = MLClient(\\n credential=credential,\\n subscription_id=subscription_id,\\n resource_group_name=resource_group_name,\\n workspace_name=workspace_name)\\n result = []\\n for ep in ml_client.online_endpoints.list():\\n hyperlink = (\\n f\\\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\\\"\\n f\\\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\\\"\\n f\\\"MachineLearningServices/workspaces/{workspace_name}\\\"\\n )\\n cur_item = {\\n \\\"value\\\": ep.name,\\n \\\"display_value\\\": f\\\"{prefix}_{ep.name}\\\",\\n # external link to jump to the endpoint page.\\n \\\"hyperlink\\\": hyperlink,\\n \\\"description\\\": f\\\"this is endpoint: {ep.name}\\\",\\n }\\n result.append(cur_item)\\n return result\\n```\\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\\n```sh\\naz login\\naz account set --subscription \\naz configure --defaults group= workspace=\\n```\\nInstall azure dependencies.\\n```sh\\npip install azure-ai-ml\\n```\\n```sh\\npip install my-tools-package[azure]>=0.0.8\\n```\\n!dynamic list function azure\", \"start_char_idx\": 2, \"end_char_idx\": 2312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.", "document_node": "{\"id_\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d769cf68-1d72-4689-8a9c-230f570e5cd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0b39012496db8b16e127cf6868f14f256d4316bf3b5682ae7057f2c021b207f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"text\": \"I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\\n\\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\\n\\n\\\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\\\"\\n\\nIf this occurs, follow these troubleshooting steps:\\n\\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.\", \"start_char_idx\": 2, \"end_char_idx\": 627, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.", "document_node": "{\"id_\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5e9e5a08-19ff-47b6-b70e-73ece4cea736\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"058be840749f87c3d4c1a9800979db634ce796b011d542b9d12e4b56f07dca74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"text\": \"Create and use your own custom strong type connection\\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections.", "document_node": "{\"id_\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c9f2fdac-08db-4edb-b3c6-a9088b3a70c8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"709f637c22d9b3f7a184550a7328629e9d8e7db1ca51f15982c8e50964ab1d43\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"text\": \"What is a Custom Strong Type Connection?\\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\\n\\n* Enhanced user experience - no need to manually enter connection keys.\\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\\n* Central location to view available keys and data types.\\n\\nFor other connections types, please refer to Connections.\", \"start_char_idx\": 2, \"end_char_idx\": 534, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fab38a19-7a14-4dbd-bab2-26cfcbc1a9bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cc0011738c8a85337bf926c06c918fa10b64f15184d623d4260ff99b5f86b18a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 230, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation.", "document_node": "{\"id_\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79cde2db-d429-4144-9fef-ecf1150f0b58\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef847fe7289c00e59ef01840ff34bece9995f06b5a69fc566387050ad2b15b33\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"text\": \"Create a custom strong type connection\\nFollow these steps to create a custom strong type connection:\\n\\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\\n\\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\\n\\n3. Document with docstrings explaining each key.\\n\\nFor example:\\n\\n```python\\nfrom promptflow.connections import CustomStrongTypeConnection\\nfrom promptflow.contracts.types import Secret\\n\\n\\nclass MyCustomConnection(CustomStrongTypeConnection):\\n \\\"\\\"\\\"My custom strong type connection.\\n\\n :param api_key: The api key.\\n :type api_key: Secret\\n :param api_base: The api base.\\n :type api_base: String\\n \\\"\\\"\\\"\\n api_key: Secret\\n api_base: str = \\\"This is a fake api base.\\\"\\n\\n```\\n\\nSee this example for a complete implementation.\", \"start_char_idx\": 2, \"end_char_idx\": 883, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:", "document_node": "{\"id_\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7387e95-ab5a-4a70-9c85-229d8acee9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3bbcd908601f7bcffce92d9d792b4b62c388bdf1d0303c84e7b579cf80efc9e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"text\": \"Use the connection in a flow\\nOnce you create a custom strong type connection, here are two ways to use it in your flows:\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow", "document_node": "{\"id_\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a3bd599a-a90a-4cbb-8037-6a13b6dd9c48\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ceaee00a227e4d995d979afa9533af34f51be8bf867a6b10088d37d2a5cca1c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"text\": \"With Package Tools:\\n\\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\\n\\n2. Develop a flow with custom tools. Please take this folder as an example.\\n\\n3. Create a custom strong type connection using one of the following methods:\\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\\n !create_custom_strong_type_connection_in_node_interface\\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\\n !create_custom_strong_type_connection_add_sign\\n - Click 'Create connection' plus sign in the Custom category.\\n !create_custom_strong_type_connection_in_custom_category \\n\\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\\n!custom_strong_type_connection_template\\n\\n5. Run the flow with the created custom strong type connection.\\n!use_custom_strong_type_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 955, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow", "document_node": "{\"id_\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"289b3241-2041-473c-bb43-232c26f7ad82\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b254e2ca79e4eb95b116cabc8863efc8ecc1d1d1e321860eef0efbe3513b0056\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"text\": \"With Script Tools:\\n\\n1. Develop a flow with python script tools. Please take this folder as an example.\\n\\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\\n !custom\\n\\n3. Run the flow with the created custom connection.\\n !use_custom_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```", "document_node": "{\"id_\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9ff5578c-d9c8-4600-8fd2-17be1c3a47bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f490870dcb22fb75d51c9cf96bd148cca6be0f1023c770decb6160254ac5c9a9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"text\": \"Local to cloud\\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\\n\\nPlease refer to Run prompt flow in Azure AI for more details.\\n\\nHere is an example command:\\n```\\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection\\\\data.jsonl --runtime test-compute\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 687, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs", "document_node": "{\"id_\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec0fe169-0696-4b09-a1d4-5378bd80aae4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d1005131a9440a9cbe7be4a33e90326f422b8cce59ff3596ce0213b8cc1def9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.", "document_node": "{\"id_\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"696d6411-2b2e-4bae-88ec-df4715c2cb9c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986a6c2ecd58baffe38dd2942c83b8d33b868ae0a3a4a0a718ebc8c9dca4be53\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"text\": \"I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\\n\\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.\", \"start_char_idx\": 2, \"end_char_idx\": 317, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.", "document_node": "{\"id_\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7fa0f6dc-819e-4c87-8266-b5a9118914d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf6d565ab14197fe3684bddae73d8a73ef4207c61eb95247d99490c74d2d9e7e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"text\": \"Customizing an LLM tool\\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.", "document_node": "{\"id_\": \"60235800-c278-4134-8278-8e27e077672b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6223b1c5-30ec-4887-8019-87b5b08719b0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d4e6526ecfa0dc58bcb2f4ffe54c63f3992a85dd43b94c87bf3443adebc570f7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 103, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```", "document_node": "{\"id_\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6cf8beb9-6705-40b5-b808-781ec0951cc0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6803b97e70221d067b2043774c8b82ade81fdc957a43c72442bb8d905c46b6b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"text\": \"How to customize an LLM tool\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \\n\\nDevelop the tool code as in this example.\\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\\n\\n ```python\\n from jinja2 import Template\\n from promptflow import tool\\n from promptflow.connections import CustomConnection\\n from promptflow.contracts.types import PromptTemplate\\n\\n\\n @tool\\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\\n # Customize your own code to use the connection and prompt here.\\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\\n return rendered_prompt\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 968, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool", "document_node": "{\"id_\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"82bdb8e8-61f7-4a8f-a7f5-11b155607365\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2cf80cfa83e508b387c2eb96683e4e830b00ddaf57323fd26f63ac87e110d0ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"text\": \"Use the tool in VS Code\\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \\n- There is a node named \\\"my_custom_llm_tool\\\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \\n!use_my_custom_llm_tool\", \"start_char_idx\": 2, \"end_char_idx\": 410, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.", "document_node": "{\"id_\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cd195a3-97b4-4a97-82bd-c7d0e87ac685\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"112eaf9f4b6fd25ac3da2887c1935dc9baf039898a60471bebff81abb7c727ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"text\": \"Using file path as tool input\\n\\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\\n\\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 530, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.", "document_node": "{\"id_\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7568039d-4551-48fa-9297-ffb37efc43cf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"59cfa4561fe4293365a4c24a5b539aa6f87ff3607a91d2e043ab8601cec1281a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"text\": \"Prerequisites\\n\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using File Path as Package Tool Input", "document_node": "{\"id_\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"26a93b18-a56a-4cdb-929c-e140981115aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"53b32a0cdc76e7c0bbcc4dc06ef8c4956aa75f189a74a5c1c249410a75f556b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"text\": \"Using File Path as Package Tool Input\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool", "document_node": "{\"id_\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ce61fc15-2cdb-4a63-8987-134e03eb1b6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"281ae66cc1678a8b7eab1188b5b3f2f788aae682ca1ab5226c276b1438877cd8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"text\": \"How to create a package tool with file path input\\n\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\\n\\nAdd a `FilePath` input for your tool, like in this example.\\n\\n```python\\nimport importlib\\nfrom pathlib import Path\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 328, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath", "document_node": "{\"id_\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35d2d03c-9329-41d3-8daf-72bc10887d9b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86d6634bc35fe36a0c204adc8d64ddc65da434342731d413778eb0d1a15923f2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"text\": \"1. import the FilePath type\\nfrom promptflow.contracts.types import FilePath\", \"start_char_idx\": 2, \"end_char_idx\": 77, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.", "document_node": "{\"id_\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"333e8f14-0e51-4937-ba22-d6ecd8476ab9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0d3447a096e1bb3aa918cbd4757bea0a31384731c63c27e170e05d8cd82a188a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"text\": \"2. add a FilePath input for your tool method\\n@tool()\\ndef my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n\\n return new_module.hello(input_text) \\n```\\n\\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.\", \"start_char_idx\": 2, \"end_char_idx\": 427, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow", "document_node": "{\"id_\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7015a1ed-1b19-4e4b-9655-112c9e4e9d22\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"11825ea60a67309ba91e6cb42883fb16318dc1f0f387ff5c3698c09b6e09813f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"text\": \"Use tool with a file path input in VS Code extension\\n\\nFollow steps to build and install your tool package and use your tool from VS Code extension.\\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\\n\\n- There is a node named \\\"Tool_with_FilePath_Input\\\" with a `file_path` type input called `input_file`.\\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\\n\\n !use file path in flow\", \"start_char_idx\": 2, \"end_char_idx\": 487, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool", "document_node": "{\"id_\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd07b5eb-b7cc-42a6-ad08-b9576bd69f78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b1e8f36cab52aa8392c7af80f8578d3cccdb448d4aa2d78149acaa3a2054980c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"text\": \"Using File Path as Script Tool Input\\n\\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\\n\\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\\n ```python\\n import importlib\\n from pathlib import Path\\n from promptflow import tool\\n # 1. import the FilePath type\\n from promptflow.contracts.types import FilePath\\n\\n # 2. add a FilePath input for your tool method\\n @tool\\n def my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n \\n return new_module.hello(input_text) \\n ```\\n\\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\\n \\n !use file path in script tool\", \"start_char_idx\": 2, \"end_char_idx\": 1206, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ", "document_node": "{\"id_\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69991809-43a1-45e0-a7ed-543d5244ca8d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d69baeb0f63d28094f13c861f5b2704b30234f6ee523cbf5dbd3e40438e496a6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"text\": \"FAQ\", \"start_char_idx\": 2, \"end_char_idx\": 5, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.", "document_node": "{\"id_\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"412a990a-7993-48bb-8dae-a040894517aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef4ca3b0ff6e914f8fe374f18dc27d6bcf687fe1838060a4d95ee76c82ba5bb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"text\": \"What are some practical use cases for this feature?\\nThe `FilePath` input enables several useful workflows:\\n\\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\\n\\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.\", \"start_char_idx\": 2, \"end_char_idx\": 605, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.", "document_node": "{\"id_\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb38a3ca-cfe8-4dca-9b10-2466376b3300\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f471b7d48ccb913477b732b2d731cc7b4f592655595022c777f9e92c1ed4808\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"text\": \"Use streaming endpoints deployed from prompt flow\\n\\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\\n\\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\\n\\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\\n\\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.\", \"start_char_idx\": 2, \"end_char_idx\": 835, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png", "document_node": "{\"id_\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"706956f6-48c9-41a9-bb1c-da5a86236d6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3e1a444f441a07ab2df4fd50af04ae49bfb3b215a2bc6535f454b0306e8696e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"text\": \"Create a streaming enabled flow\\n\\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\\n\\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\\n ```jinja\\n {# Sample prompt template for LLM node #}\\n\\n system:\\n You are a helpful assistant.\\n\\n user:\\n {{question}}\\n ```\\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\\n ```python\\n from promptflow import tool\\n\\n # Sample code echo input by yield in Python tool node\\n\\n @tool\\n def my_python_tool(paragraph: str) -> str:\\n yield \\\"Echo: \\\"\\n for word in paragraph.split():\\n yield word + \\\" \\\"\\n ```\\n\\nIn this guide, we will use the \\\"Chat with Wikipedia\\\" sample flow as an example. This flow processes the user\\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\\n\\n!chat_wikipedia.png\", \"start_char_idx\": 2, \"end_char_idx\": 1372, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page.", "document_node": "{\"id_\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6c888e5e-8cc3-40a3-957c-c9490fb07aa7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf83dc0a7e113999480393c58b334373aff1e4fe2bdbed0ff974e231287e4ce7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"text\": \"Deploy the flow as an online endpoint\\n\\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\\n\\nFollow this guide to deploy your flow as an online endpoint.\\n\\n> [!NOTE]\\n> \\n> You can follow this document to deploy an online endpoint.\\n> Please deploy with runtime environment version later than version `20230816.v10`.\\n> You can check your runtime version and update runtime in the run time detail page.\", \"start_char_idx\": 2, \"end_char_idx\": 513, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:", "document_node": "{\"id_\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98c6ee2b-c91e-450b-964c-eb2654ba13bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0034781020f8eb762eb657bec70cf919844120f8791674e17ff9ec21750f2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"text\": \"Understand the streaming process\\n\\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\\n\\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\\n\\nTo understand the streaming process, consider the following steps:\\n\\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \\\"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\\\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\\n > [!NOTE]\\n > \\n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\\n \\n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\\n - If the `Accept` header specifies other media types, such as `text/html`:\\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\\n > Note: Please refer handle errors for details.\\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\\n\\nLet\\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\\n\\nThe overall process works as follows:\", \"start_char_idx\": 2, \"end_char_idx\": 2788, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response.", "document_node": "{\"id_\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddaf9efd-9ac9-4829-a54c-1648089d8d70\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"680ad8077e320e6e398a84f918cd7befe171f7bb12e18aee8904d3e2647b006f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"text\": \"0. The client sends a message to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Hello\\\",\\n \\\"chat_history\\\": []\\n}\\n```\\n> [!NOTE]\\n> \\n> The `Accept` header is set to `text/event-stream` to request a stream response.\", \"start_char_idx\": 2, \"end_char_idx\": 326, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.", "document_node": "{\"id_\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"821fdf27-98c6-43a4-8a2f-c784651596bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3aabc69a0ec2b4ab4cf0c35722875bb5c3a8751390b1eeafc540cc6ab9fd19d8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"text\": \"1. The server sends back the response in streaming mode.\\n\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Hello\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" How\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" assist\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" today\\\"}\\n\\ndata: {\\\"answer\\\": \\\" ?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\\n\\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\\n\\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\\n\\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.\", \"start_char_idx\": 2, \"end_char_idx\": 944, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"912d0e1f-a746-471c-a2a4-71fc2730e575\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d85b5ace9efc60427c9f464f9645bb0589929e638b563f9b7da4c5a5db69026\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Glad to know you!\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"Hello\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"answer\\\": \\\"Hello! How can I assist you today?\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 491, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```", "document_node": "{\"id_\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48347717-5e52-4331-8d92-6a7c54fe3d03\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554b3afb5397fc0a38ddb0164a88ae48a2e944d9d06f047d66f849aed83187aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Nice\\\"}\\n\\ndata: {\\\"answer\\\": \\\" to\\\"}\\n\\ndata: {\\\"answer\\\": \\\" know\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" too\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" there\\\"}\\n\\ndata: {\\\"answer\\\": \\\" anything\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" help\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" with\\\"}\\n\\ndata: {\\\"answer\\\": \\\"?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 607, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "4. The chat continues in a similar way.", "document_node": "{\"id_\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ac508813-a33c-4c2c-a3d1-773e79aef114\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6a748b536cb6dbb48de3c2fc76dfaee7b3ac7bb7e92983c1f6a60a2789577178\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"text\": \"4. The chat continues in a similar way.\", \"start_char_idx\": 2, \"end_char_idx\": 41, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user.", "document_node": "{\"id_\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3fd257bf-5cf8-4f99-bffc-e3bbc6f78390\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56eac9e90da9529ab6e04074e76b19d92a2b351f7e19b21d8973f970dc189c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"text\": \"Handle errors\\n\\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\\n\\nIf the response code is \\\"424 Model Error\\\", it means that the error is caused by the model\\u2019s code. The error response from a PromptFlow model always follows this format:\\n\\n```json\\n{\\n \\\"error\\\": {\\n \\\"code\\\": \\\"UserError\\\",\\n \\\"message\\\": \\\"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\\\",\\n }\\n}\\n```\\n* It is always a JSON dictionary with only one key \\\"error\\\" defined.\\n* The value for \\\"error\\\" is a dictionary, containing \\\"code\\\", \\\"message\\\".\\n* \\\"code\\\" defines the error category. Currently, it may be \\\"UserError\\\" for bad user inputs and \\\"SystemError\\\" for errors inside the service.\\n* \\\"message\\\" is a description of the error. It can be displayed to the end user.\", \"start_char_idx\": 2, \"end_char_idx\": 851, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to consume the server-sent events", "document_node": "{\"id_\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a6fd14f-f375-4da2-a24b-0cafcf1fddf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efe8860eada88de2417ef06be8a0990d2deea819d95cba2e97b9ca1a432e4c54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"text\": \"How to consume the server-sent events\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```", "document_node": "{\"id_\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dd27869b-15cf-42ca-b7e6-50aa08ba0d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7591010f02260b9174a1b2251dc262f58eb1a52ae423e651964800b13059af4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"text\": \"Consume using Python\\n\\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\\n\\n```bash\\npip install sseclient-py \\n```\\n\\nA sample usage would like:\\n\\n```python\\nimport requests \\nfrom sseclient import SSEClient \\nfrom requests.exceptions import HTTPError \\n\\ntry:\\n response = requests.post(url, json=body, headers=headers, stream=stream)\\n response.raise_for_status()\\n\\n content_type = response.headers.get('Content-Type')\\n if \\\"text/event-stream\\\" in content_type:\\n client = SSEClient(response)\\n for event in client.events():\\n # Handle event, i.e. print to stdout\\n else:\\n # Handle json response\\n\\nexcept HTTPError:\\n # Handle exceptions\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 792, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.", "document_node": "{\"id_\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"42e4799e-96c2-4780-a62c-923dc6c72ced\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ee102f88249caf546d0c0bdafd13b8f1a212f9d0775fc8151940e1fee75512c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"text\": \"Consume using JavaScript\\n\\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app", "document_node": "{\"id_\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c8f1f5f-4639-4ce0-a7e3-73399238b474\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3f1b447e5173f4bafc67db22b703f07422d77028dcf992b0553bd73fcd33c9b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"text\": \"A sample chat app using Python\\n\\nHere is a sample chat app written in Python.\\n(Click here to view the source code.)\\n\\n!chat_app\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.", "document_node": "{\"id_\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da359dbe-b196-465f-a58b-923cfa17400e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d36f27b1e6799c33c3a5f8115b7c7535edcea14977513849b56331f899eed90f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"text\": \"Advance usage - hybrid stream and non-stream flow output\\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \\u201cChat with Wikipedia\\u201d flow, you may want to get not only LLM\\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\\u2019s answer and non-stream URL list.\\n\\nIn the sample \\\"Chat With Wikipedia\\\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\\n\\n!chat_wikipedia_dual_output_center.png\\n\\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.\", \"start_char_idx\": 2, \"end_char_idx\": 805, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```", "document_node": "{\"id_\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"14f0a5dd-312e-4539-b900-5b291142a148\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ed2ed3f2b32332867a54f69c94b86e84eeedfce3c36e9a8010183b04b170e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"text\": \"0. The client sends a message to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\",\\n \\\"chat_history\\\": []\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d9f464-762e-4146-9352-9a808af3fde8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"02a6bf0f2539cc26435514fe55f4f59572376600cce1efc190c79b9fcd743123\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"text\": \"1. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\", \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 747, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"016b2ee8-acf4-4bdc-94c7-79463ab4a7db\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0aa2e2ac63ba13015313fe66dfbb8ec4203540014741ea1281303ddb606424c7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When did OpenAI announce GPT-4? How long is it between these two milestones?\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"url\\\": [\\n \\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\",\\n \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"\\n ],\\n \\\"answer\\\": \\\"ChatGPT was launched on November 30, 2022. \\\\n\\\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 833, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9fe0c1e9-3ca5-4c67-9d7c-bb987940b686\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29379ee510ab86ed5cf7ccd99fa4be6d0d1580d210182a61323bbbd0a9a44089\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \\\", \\\"https://en.wikipedia.org/w/index.php?search=Microsoft \\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Open\\\"}\\n\\ndata: {\\\"answer\\\": \\\"AI\\\"}\\n\\ndata: {\\\"answer\\\": \\\" released\\\"}\\n\\ndata: {\\\"answer\\\": \\\" G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"-\\\"}\\n\\ndata: {\\\"answer\\\": \\\"4\\\"}\\n\\ndata: {\\\"answer\\\": \\\" in\\\"}\\n\\ndata: {\\\"answer\\\": \\\" March\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" The\\\"}\\n\\ndata: {\\\"answer\\\": \\\" time\\\"}\\n\\ndata: {\\\"answer\\\": \\\" between\\\"}\\n\\ndata: {\\\"answer\\\": \\\" these\\\"}\\n\\ndata: {\\\"answer\\\": \\\" two\\\"}\\n\\ndata: {\\\"answer\\\": \\\" milestones\\\"}\\n\\ndata: {\\\"answer\\\": \\\" is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" approximately\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\" months\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1458, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::", "document_node": "{\"id_\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e02f01b8-6709-4920-9a8b-7e2c5e77be44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4fa90920b48a86b6763c89f59b0bddae5ecf0338d4fd85cb546c4cddc5864ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"text\": \"Execute flow as a function\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.", "document_node": "{\"id_\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ea36d385-1925-46e4-a5b7-e77f0f3cc6ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f1f3fd175e8d9c564036921a8f4759cac8cbcb556a37d3504935f460547b059\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"text\": \"Overview\\n\\nPromptflow allows you to load a flow and use it as a function in your code.\\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```", "document_node": "{\"id_\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fb1e5741-98bd-4b28-88dd-9c503d0421ef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f813adeab56a408bcb78b566016ee117476fd8356ae2dafe911f856ec3ca07ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"text\": \"Load an invoke the flow function\\n\\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\\nThen you can consume the flow object like a function by providing key-value arguments for it.\\n\\n```python\\nf = load_flow(\\\"../../examples/flows/standard/web-classification/\\\")\\nf(url=\\\"sample_url\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 330, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.", "document_node": "{\"id_\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"91e9d667-cfbc-4f4e-9240-09036f81dfc7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bce2f8b33b0e9c233454a16cc5975de252451fb6c45f3ad82274458c869fa0aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"text\": \"Config the flow with context\\n\\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)", "document_node": "{\"id_\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24e752d6-0029-4218-94ca-93a1465077b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d7195051357847107c3e1134dd358ec6063a42599855d090ebf34cb8707d0774\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"text\": \"Load flow as a function with in-memory connection override\\n\\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\\n\\n```python\\nfrom promptflow.entities import AzureOpenAIConnection\\n\\nconnection_obj = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=api_key,\\n api_base=api_base,\\n api_type=\\\"azure\\\",\\n api_version=api_version,\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```", "document_node": "{\"id_\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dde478bf-d6cb-43a8-b1a4-8d8d35f25e0f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ed8c2e142e9b716c24dadc03b5b75782fb42f44c8ed62da6f2131b6c418f2eb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"text\": \"no need to create the connection object.\\nf.context = FlowContext(\\n connections={\\\"classify_with_llm\\\": {\\\"connection\\\": connection_obj}}\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.", "document_node": "{\"id_\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a9785096-c148-4ec8-9a62-f6b9f80ef601\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1fcfc555a6a8a8a1950f5352afbdd252f325d853dbef81815bb12d212a5afe8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"text\": \"Local flow as a function with flow inputs override\\n\\nBy providing overrides, the original flow dag will be updated in execution time.\\n\\n```python\\nf.context = FlowContext(\\n # node \\\"fetch_text_content_from_url\\\" will take inputs from the following command instead of from flow input\\n overrides={\\\"nodes.fetch_text_content_from_url.inputs.url\\\": sample_url},\\n)\\n```\\n\\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.\", \"start_char_idx\": 2, \"end_char_idx\": 565, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\"", "document_node": "{\"id_\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6b681357-4cac-4553-b6a5-9df520eb030b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac1d912138d7d912b5c51e55b4e77d89d14ff84ee46ca9d1ee92acd7d9898b59\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"text\": \"Load flow as a function with streaming output\\n\\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\\n\\n```python\\nf = load_flow(source=\\\"../../examples/flows/chat/basic-chat/\\\")\\nf.context.streaming = True\\nresult = f(\\n chat_history=[\\n {\\n \\\"inputs\\\": {\\\"chat_input\\\": \\\"Hi\\\"},\\n \\\"outputs\\\": {\\\"chat_output\\\": \\\"Hello! How can I assist you today?\\\"},\\n }\\n ],\\n question=\\\"How are you?\\\",\\n)\\n\\n\\nanswer = \\\"\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage.", "document_node": "{\"id_\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bbbd143-9995-4367-939e-0c831eb263fe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2cfa7009b4997d3fde306b94dbf03de21819f05a14d0aaca580fc15eb62a26d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"text\": \"the result will be a generator, iterate it to get the result\\nfor r in result[\\\"answer\\\"]:\\n answer += r\\n\\n```\\n\\nReference our sample for usage.\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow", "document_node": "{\"id_\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07fb8988-8ef2-4450-aa41-2d21c42ff60a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a44b5c7aad060be11eb17db2bce6368d458f1e720941d3c50c807c071a6ce513\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"text\": \"Next steps\\n\\nLearn more about:\\n\\n- Flow as a function sample\\n- Deploy a flow\", \"start_char_idx\": 2, \"end_char_idx\": 76, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Frequency asked questions (FAQ)", "document_node": "{\"id_\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cb9f4a0f-e680-47fc-8f5d-5b223d51d083\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"743917481836b00908b09ff34a3d165a53a55bbd846807af36b7bb80a22a628c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"text\": \"Frequency asked questions (FAQ)\", \"start_char_idx\": 2, \"end_char_idx\": 33, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "General", "document_node": "{\"id_\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c597cc0b-d110-4165-8c96-53d36acef69d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"814d7155ef3529ff69b2385fcb080cd2c7b7fccacefb5d13c76ea02c151e3825\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"text\": \"General\", \"start_char_idx\": 2, \"end_char_idx\": 9, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.", "document_node": "{\"id_\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0fe4dd5d-e4c5-40ed-98e7-a044021dbf86\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1c42f40448725a9a0bd02a07496b82437c4fbad22447c717ff5a6f9ac9b220e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"text\": \"Stable vs experimental\\n\\nPrompt flow provides both stable and experimental features in the same SDK.\\n\\n|Feature status | Description | \\n|----------------|----------------|\\nStable features\\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.\", \"start_char_idx\": 2, \"end_char_idx\": 1143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details.", "document_node": "{\"id_\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bb3c750-f12d-4808-ab89-acf161dfd91e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6beadd06f30b207f672c997719c336539e7faf8ef36feaf44e40f65c1b4fa868\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"text\": \"OpenAI 1.x support\\nPlease use the following command to upgrade promptflow for openai 1.x support:\\n```\\npip install promptflow>=1.1.0\\npip install promptflow-tools>=1.0.0\\n```\\nNote that the command above will upgrade your openai package a version later than 1.0.0, \\nwhich may introduce breaking changes to custom tool code.\\n\\nReach OpenAI migration guide for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 369, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Troubleshooting", "document_node": "{\"id_\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e9acc577-1cbb-429e-970d-7c98723202ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af390d4c747d81b170f3d982c0a82884e61001ce8fe19ffbddc01b21b7d24626\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"text\": \"Troubleshooting\", \"start_char_idx\": 2, \"end_char_idx\": 17, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.", "document_node": "{\"id_\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6ba934f9-e5d6-4550-8a2f-0c6be54cd508\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8e9e6602be667f9cba044453ac50a9f815cf9662bbf038f534f5481bbbc3305b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"text\": \"Connection creation failed with StoreConnectionEncryptionKeyError\\n\\n```\\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\\n```\\n\\nThis error raised due to keyring can't find an available backend to store keys.\\nFor example macOS Keychain and Windows Credential Locker\\nare valid keyring backends.\\n\\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\\n`pip install keyrings.alt`\\n\\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.\", \"start_char_idx\": 2, \"end_char_idx\": 773, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.", "document_node": "{\"id_\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7499f3d-3746-45d8-bddc-7b8e7726100f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fb9686bc123c832e95558b925d4fb46cc4c621ce1ad04658d3092dc3e77c89\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"text\": \"Pf visualize show error: \\\"tcgetpgrp failed: Not a tty\\\"\\n\\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\\n\\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.\", \"start_char_idx\": 2, \"end_char_idx\": 367, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.", "document_node": "{\"id_\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0a6a1158-c713-4412-b59d-b85f18e89f0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"67bd1cc4115725959bb26b2e210e9bc34bdafb0f300364d873e67e7b6d1a203c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"text\": \"Installed tool not appearing in VSCode Extension tool list\\n\\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\\n\\n!VSCode Extension tool list\\n\\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\\n\\n1. Open the VSCode Extension window.\\n\\n2. Bring up the command palette by pressing \\\"Ctrl+Shift+P\\\".\\n\\n3. Type and select the \\\"Developer: Reload Webviews\\\" command. \\n\\n4. Wait a moment for the tool list refreshing.\\n\\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.\", \"start_char_idx\": 2, \"end_char_idx\": 716, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img", "document_node": "{\"id_\": \"98caef46-1716-47c8-8950-80296635edb6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8b886825-981c-4d7a-a456-b29e07a0f2c3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6b854d9357a3adff77eaf7bdce41cc3375c66d93c1da46c6f7928d8fc0c13fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"text\": \"Set logging level\\n\\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\\n\\n!img\\n\\nCompare to the serving logs with `WARNING` level:\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.", "document_node": "{\"id_\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"576f95f6-92d9-483f-822a-0ce9bf0bd395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45f83f4fb0b797a2d06fb8a2f9cfeb3c6c9008f2be62d661550b4b1311b1934a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"text\": \"Set environment variables\\n\\nCurrently, promptflow supports the following environment variables:\\n\\n**PF_WORKER_COUNT** \\n\\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\\n\\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\\n\\nWhen you modify the concurrency, please consider 2 points:\\n\\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\\n\\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\\n\\n```\\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\\n```\\nTPM: token per minute, capacity rate limit of your LLM endpoint\\n\\nduration_seconds: single flow run duration in seconds\\n\\ntoken_count: single flow run token count\\n\\n\\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\\n\\n**PF_BATCH_METHOD**\\n\\nValid for batch run only. Optional values: 'spawn', 'fork'. \\n\\n**spawn**\\n\\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\\n\\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\\n \\n**fork**\\n\\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\\n\\n2. The process starts faster as it doesn't need to reinitialize resources.\\n \\nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.\", \"start_char_idx\": 2, \"end_char_idx\": 2366, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```", "document_node": "{\"id_\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1bb38f65-df51-4e35-9339-b39205a74d42\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5ffb3a0055a7127117140f63d34e4ee966af213db99b4fa728c673465b4004c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"text\": \"You can configure environment variables in the following ways\\n\\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\\\"2\\\" PF_BATCH_METHOD=\\\"spawn\\\"```.\\n\\n2. If you are using SDK, you can specify environment variables when creating run. Example: \\n\\n``` python\\n pf = PFClient(\\n credential=credential,\\n subscription_id=\\\"\\\",\\n resource_group_name=\\\"\\\",\\n workspace_name=\\\"\\\",\\n )\\n\\n flow = \\\"web-classification\\\"\\n data = \\\"web-classification/data.jsonl\\\"\\n runtime = \\\"example-runtime-ci\\\"\\n\\n environment_variables = {\\\"PF_WORKER_COUNT\\\": \\\"2\\\", \\\"PF_BATCH_METHOD\\\": \\\"spawn\\\"}\\n\\n # create run\\n base_run = pf.run(\\n flow=flow,\\n data=data,\\n runtime=runtime,\\n environment_variables=environment_variables,\\n )\\n```\\n\\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\\n\\n``` yaml\\n name: flow_name\\n display_name: display_name\\n flow: flow_folder\\n data: data_file\\n column_mapping:\\n customer_info: \\n history: \\n environment_variables:\\n PF_WORKER_COUNT: \\\"2\\\"\\n PF_BATCH_METHOD: \\\"spawn\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1240, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it.", "document_node": "{\"id_\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2d12cb4e-9982-46b1-8020-5a397a5c70ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27490f9ccc0a4ef12bcef73484eb8f041e969282c05eff50bb23a31b4394ca93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"text\": \"Initialize and test a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, customer can initialize a flow and test it.\", \"start_char_idx\": 2, \"end_char_idx\": 208, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow.", "document_node": "{\"id_\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"223ae55b-31d0-4a3f-a845-e2cbb48d2174\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a987c0ab8aa00ab20a17431c70079e376558edd598e742211a1b6d6323108503\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"text\": \"Initialize flow\\n\\nCreating a flow folder with code/prompts and yaml definitions of the flow.\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a5ad4e4-84f4-4725-8096-3096c1ce097f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9d2f6bed32465c8afd0d71f4ff8109ac9daee9f05c58a3b9afe2016bca66aa5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"text\": \"Initialize flow from scratch\\n\\nPromptflow can create three types of flow folder:\\n- standard: Basic structure of flow folder.\\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 525, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a flow\npf flow init --flow", "document_node": "{\"id_\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a66b4440-7ab7-4a0a-8e3e-cf53ce0da183\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c55a21ae37e2c8abc954550c17e8d4ae89c001cbd51afbdf6250026ab8111cd7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"text\": \"Create a flow\\npf flow init --flow\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder", "document_node": "{\"id_\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3979a8ce-fe87-4ab5-b144-4b734aa35c25\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"184c77063135f92e2154daff06d061bfd4a0dc94f3d65875b712e2986daca02a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"text\": \"Create a chat flow\\npf flow init --flow --type chat\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse VS Code explorer pane > directory icon > right click > the \\\"New flow in this directory\\\" action. Follow the popped out dialog to initialize your flow in the target folder.\\n!img\\n\\nAlternatively, you can use the \\\"Create new flow\\\" action on the prompt flow pane > quick access section to create a new flow\\n!img\\n\\n:::\\n\\n::::\\n\\n\\nStructure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n!init_flow_folder\", \"start_char_idx\": 2, \"end_char_idx\": 847, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash", "document_node": "{\"id_\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15bc22d5-c272-430d-b04a-79cfe65f18fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"66785e16e82b7ffa50adb19068670cd130f8b3dc6ab081a908061308b313ce3c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"text\": \"Create from existing code\\n\\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 414, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files", "document_node": "{\"id_\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8a15b7b7-5711-4d86-917f-4fc2036c6027\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6c03c3df69e37b72e57a0a75ca81f10041bf1c7f5b9b1a3c8506b13f6aa43f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"text\": \"Create a flow in existing folder\\npf flow init --flow --entry --function --prompt-template =\\n```\\n\\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\\n\\n!init_output\\n\\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\\n\\n!init_files\", \"start_char_idx\": 2, \"end_char_idx\": 396, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.", "document_node": "{\"id_\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95cd3374-d155-4f86-b29d-fb4bf987e22b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9422effd2aaeb2748e289c5baf349916d999564c3179e620610f11eb42dd375e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"text\": \"Test a flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::", "document_node": "{\"id_\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2aafc740-6302-4dbf-a42d-ee1dea0c6ebf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"446896168b129cd5539cb3091ff4073483ad34e324321c181d6a0901e0abd70a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"text\": \"Visual editor on the VS Code for prompt flow.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \\\"Visual editor\\\" action. Use it to open the Visual editor with GUI support.\\n\\n!img\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 300, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ee0cc84-3f98-42e6-8a67-fbdee3586ccc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b83ff835b3a805eb03482d718707c0e686d12752df5f55dce13fd7e2fcaf50a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"text\": \"Test flow\\n\\nCustomer can use CLI or VS Code extension to test the flow.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\npf flow test --flow", "document_node": "{\"id_\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd5cefe7-28c9-4bf0-9fc6-8b3609de5b5a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"229f3f16a238a91b31c7e47ac2e91406ec163f09cd791edd3eb594209a03c0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"text\": \"Test flow\\npf flow test --flow\", \"start_char_idx\": 2, \"end_char_idx\": 31, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"49dd7bd1-552d-40a9-8f03-e533f0e08d54\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ddf2f5446188a40b24a32a024a1b0544334ba529ecba86dda4f49f1d4be2129\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"text\": \"Test flow with specified variant\\npf flow test --flow --variant '${.}'\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 577, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d1ad1393-927d-41d6-8139-7e599f0f06e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"89b24a887590553199b9ee0c1b9fc51a85ab692e6db323dbdcd22c2255e9a892\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 702, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash", "document_node": "{\"id_\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4eb28b8-dc68-48de-87fe-746453fa405a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"125b62feb2a0b81e72c1bbb54a25128fe0ef760e2cf21a4de506ac04bc14cc5e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"text\": \"Test a single node in the flow\\n\\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nCustomer can execute this command to test the flow.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 337, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7b80b991-92a3-41ea-a747-36708cbc9dd2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68553f1861f970ef898e05440d384d9c431f59f1b74bb863b93bba6b233fac22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"text\": \"Test flow node\\npf flow test --flow --node \\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 419, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"18f1adbf-ecc3-4b53-8418-89329a15ce5e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd07e53bbd4061d9ac9e11b6f588c17761eb7b3a19c7444a286fc89370fc0325\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"text\": \"Test not iun the flow\\ninputs = {: } # The inputs of the node.\\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 533, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash", "document_node": "{\"id_\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd754830-349c-4e11-a781-bb24512461e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3d66f9f55eb3364c049a109ae76e0f366d5b39f746f9732b4cc63961d184d1b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"text\": \"Test with interactive mode\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 234, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1dfba4cb-27ff-46d4-9f89-6e585c66e7af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"15964bbe99b83f7830453b5a2e5113f3bef996cda9aa8ef777a98643873a429f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"text\": \"Chat in the flow\\npf flow test --flow --interactive\\n```\\n\\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\\n\\nUsing this chat flow to show how to use interactive mode.\\n\\n!chat\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\\n\\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe flow result will be streamed in the terminal as shown below.\\n\\n!streaming_output\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 1162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::", "document_node": "{\"id_\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf5960ff-bb2a-46e1-91ec-56aca552ecbd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c8c2606c9b6fb9f5472c28e53817c83a807118199ca561ac221ee50d994050db\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nfor item in flow_result[\\\"\\\"]:\\n print(item)\\n```\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 169, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bdc16d88-1916-4304-a6f7-440c9efca1ca\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82e4d3ca19496b8c5d4386adfd56d7eaa8cc032e8c7c141ef4c7e886eef46caa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"text\": \"Debug a single node in the flow\\n\\nCustomer can debug a single python node in VScode by the extension.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 374, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\n- Add conditional control to a flow", "document_node": "{\"id_\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d5caefb5-8563-48c6-814b-b513309e144c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86f72212dd70181df51676601190b6b412486d8aeeaeca9885371345ea964535\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"text\": \"Next steps\\n\\n- Add conditional control to a flow\", \"start_char_idx\": 2, \"end_char_idx\": 49, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::", "document_node": "{\"id_\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c679040-3627-4e7a-8599-ae144332c763\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bc0144e32aa85d7452b6071e6e0ac610d0995a2640ead996bc906162475a7c77\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"text\": \"Manage connections\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\\n\\n:::{note}\\nTo use azureml workspace connection locally, refer to this guide.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 422, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.", "document_node": "{\"id_\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c4ff6b8-fe67-4ec7-9eea-a84769ed42fa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9fc840fdb46639dfa7f2c0c5525c7397a8b717192d4e4fd05796d2a5443e72d7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"text\": \"Connection types\\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\\n\\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 502, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash", "document_node": "{\"id_\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48897b0d-44af-4c0a-8411-f4048af44ce9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"849f9eedece63c894efdd476e9e1bb3dde2e5c55044c6a782b51bf3bb4b48b7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"text\": \"Create a connection\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: azure_open_ai_connection\\ntype: azure_open_ai\\napi_key: \\\"\\\"\\napi_base: \\\"https://.openai.azure.com/\\\"\\napi_type: \\\"azure\\\"\\napi_version: \\\"2023-03-15-preview\\\"\\n```\\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\\nname: custom_connection\\ntype: custom\\nconfigs:\\n endpoint: \\\"\\\"\\n other_config: \\\"other_value\\\"\\nsecrets: # required\\n my_key: \\\"\\\"\\n```\\nAfter preparing the yaml file, use the CLI command below to create them:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1078, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key=", "document_node": "{\"id_\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"87222c5e-4f77-4b93-8d69-d5f7af5f06f3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0e4402c636bd9dd666a5652039e3f48b4f98339d223f75428020f237415d64fa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"text\": \"Override keys with --set to avoid yaml file changes\\npf connection create -f --set api_key=\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection", "document_node": "{\"id_\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"415192cd-10f2-45df-b939-9de5ea5c8ee0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d9fac2f2493f493188f30ca653a58bf91bee6219703e2123ffaafdb01a378519\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"text\": \"Create the custom connection\\npf connection create -f --set configs.endpoint= secrets.my_key=\\n```\\nThe expected result is as follows if the connection created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5ac1b34a-f365-46b2-af27-98df27795edb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d704aa2ec218d1b1acc8c01252d81cd49440df151dd5ec4a92ccf0fbb54a87ff\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)", "document_node": "{\"id_\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddfa8c7c-cdd4-4073-ad8c-34534a20b49a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a7db8e137fd4c7c07d1f4ae406b7ee0b2aad89be313957c12e3d2c9efdf5538\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"text\": \"Initialize an AzureOpenAIConnection object\\nconnection = AzureOpenAIConnection(\\n name=\\\"my_azure_open_ai_connection\\\", \\n api_key=\\\"\\\", \\n api_base=\\\"\\\"\\n api_version=\\\"2023-03-15-preview\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 193, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)", "document_node": "{\"id_\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86e2c793-3cb8-4ec7-bc7d-44576f1a8170\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0a0e5bcab0cc6aca9da6836e7fd11cd9442b42270019b48113f33540fb9d8d40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"text\": \"Create the connection, note that api_key will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)", "document_node": "{\"id_\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a130569c-c523-4a83-be04-b4706f124c1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"011cb400a1083e76cc32cc921b1a71a76b18dde3df75f4b224a9b9e1d9434f90\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"text\": \"Initialize a custom connection object\\nconnection = CustomConnection(\\n name=\\\"my_custom_connection\\\", \\n # Secrets is a required field for custom connection\\n secrets={\\\"my_key\\\": \\\"\\\"},\\n configs={\\\"endpoint\\\": \\\"\\\", \\\"other_config\\\": \\\"other_value\\\"}\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e783be9d-0148-44a5-ab4f-dd0523ac8334\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"751dfc933b0e96e74f8ce306a449da30d196af0146bd2bf18261f765194c180f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"text\": \"Create the connection, note that all secret values will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \\\"+\\\" icon on the top right of it and follow the popped out instructions to create your new connection.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 463, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash", "document_node": "{\"id_\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e85cc25f-3348-406f-af8a-2754d2339ac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ff8b3d46333114d6aa64b7572fc631715461e38af0f2ddf90f5bd6ceefe0483\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"text\": \"Update a connection\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe commands below show how to update existing connections with new values:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'", "document_node": "{\"id_\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3abffd3b-ed39-4218-bce7-5becbd65db6c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74e7f2cb5f8df53cffe2b8bf20c9755b3e0cd188ab67d8f242d74e36cd2d5773\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"text\": \"Update an azure open ai connection with a new api base\\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python", "document_node": "{\"id_\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"50207311-5c91-4251-a254-720a7b40926a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"73a939ef359ad24d3ddae75e1280b2e91a6cca8a37caa45b3b798800a099da3a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"text\": \"Update a custom connection\\npf connection update -n my_custom_connection --set configs.other_config='new_value'\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nThe code snippet below shows how to update existing connections with new values:\\n```python\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)", "document_node": "{\"id_\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c76ef7e2-4457-4746-aa80-44d36f3e679d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e529352592a59587b997627812a31f186d8aad0960591837b21f31fcca158ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"text\": \"Update an azure open ai connection with a new api base\\nconnection = pf.connections.get(name=\\\"my_azure_open_ai_connection\\\")\\nconnection.api_base = \\\"new_value\\\"\\nconnection.api_key = \\\"\\\" # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\", \"start_char_idx\": 2, \"end_char_idx\": 312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"63dd3856-a79f-497b-a8e0-aa61b446d692\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5025c879a00830a327e4ec3f23a86b5566cb9fa543823d37bbe40e4c5cec352\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"text\": \"Update a custom connection\\nconnection = pf.connections.get(name=\\\"my_custom_connection\\\")\\nconnection.configs[\\\"other_config\\\"] = \\\"new_value\\\"\\nconnection.secrets = {\\\"key1\\\": \\\"val1\\\"} # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f6d9da7-52eb-4abf-8a2e-a927ee735541\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d3ea86a42100eb1fe366be6811c4eeaac9dfb41944fb89ba80ff1b66f248a615\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"text\": \"List connections\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\\n```bash\\npf connection list\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 415, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f51d9a42-127f-4ea9-9792-e149e8a38a7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02057374-00f7-431d-9da0-156db1202852\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5700cd94662430caae88bb657f1bca9ea785a2616bc964557182744191e247dc\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"text\": \"List and print connections\\nconnection_list = pf.connections.list()\\nfor connection in connection_list:\\n print(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 191, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9829818d-2389-4b7a-b824-87ff80e4e5bc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50527ec74e94bfc190f0dbf98b325f1f2e187c5ac5ec86d7a09dfee41c9592c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"text\": \"Delete a connection\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nDelete a connection with the following command:\\n```bash\\npf connection delete -n \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nDelete a connection with the following code snippet:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 279, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e31a56f7-dfde-4662-a545-e3382f5d2395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"09e1d45a-e995-4845-9819-61a50a7e3fcc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62a9b42d19dc3a2618a57b3123475f3e48b57c65cef1d43fd9918153ffb040ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"text\": \"Delete the connection with specific name\\nclient.connections.delete(name=\\\"my_custom_connection\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI.", "document_node": "{\"id_\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"345ef80f-a13b-4a7a-a85c-fcb140faf879\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d5386667d921191043732d28b80d2062181886d4c8ab54880eaed2e9a80f6a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"text\": \"Next steps\\n- Reach more detail about connection concepts.\\n- Try the connection samples.\\n- Consume connections from Azure AI.\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run", "document_node": "{\"id_\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb5ce587-ed3b-4933-90a2-cd69af33569a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f5704af61f5056221d2e79bc09b64b5866186f2a9d92c1973198f7ad601ff0c2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"text\": \"Manage runs\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \\n\\nIn general:\\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\\n\\nLet's take a look at the following topics:\\n\\n- Manage runs\\n - Create a run\\n - Get a run\\n - Show run details\\n - Show run metrics\\n - Visualize a run\\n - List runs\\n - Update a run\\n - Archive a run\\n - Restore a run\", \"start_char_idx\": 2, \"end_char_idx\": 668, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash", "document_node": "{\"id_\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2f925fe9-ce2c-4854-b77b-13180f4a0960\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2128e989c9a49e28690407060252f2ed66ab45c3e599f65cfcd28e80fa2cdde9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"text\": \"Create a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nTo create a run against bulk inputs, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../web_classification\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n url: \\\"${data.url}\\\"\\nvariant: ${summarize_text_content.variant_0}\\n```\\n\\nTo create a run against existing run, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../classification_accuracy_evaluation\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n groundtruth: \\\"${data.answer}\\\"\\n prediction: \\\"${run.outputs.category}\\\"\\nrun: \\n```\\n\\nReference here for detailed information for column mapping.\\nYou can find additional information about flow yaml schema in Run YAML Schema.\\n\\nAfter preparing the yaml file, use the CLI command below to create them:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 940, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create the flow run\npf run create -f", "document_node": "{\"id_\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e8f49d4b-09cb-4725-b400-3e6a57e6f756\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1f5b6613de87d844d48e200c9b9c9059eeec4f91a3db91eecb7cdab65d19814c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"text\": \"create the flow run\\npf run create -f\", \"start_char_idx\": 2, \"end_char_idx\": 38, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run", "document_node": "{\"id_\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69b30e6f-ae04-4662-b070-0d2f621ebefe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4633642239f0ea5e8c401ec55305ae8b31da7edc8a8b8d683eb99d6fe9106406\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"text\": \"create the flow run and stream output\\npf run create -f --stream\\n```\\n\\nThe expected result is as follows if the run is created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import Run\", \"start_char_idx\": 2, \"end_char_idx\": 409, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7d2a225f-8af5-476f-89c9-80c92eeb0470\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad254fb5c3bfa9051eb14e7387114c2a5c1c76bbb931108fe180d2bb19b7054\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)", "document_node": "{\"id_\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd6f0ea0-d59d-4713-9cd0-ba3eb0e65942\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48b09a6ad917a748e77953d709c4a0363847b171256aca5776de986d2a3403cf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"text\": \"Initialize an Run object\\nrun = Run( \\n flow=\\\"\\\",\\n # run flow against local data or existing run, only one of data & run can be specified. \\n data=\\\"\\\",\\n run=\\\"\\\",\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n variant=\\\"${summarize_text_content.variant_0}\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 264, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d537c095-e0b4-4578-bd01-a7a6ecfdaa26\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbdad1ed5255e045338bc1ee9997c8440345b0219f5f7c566599525647199619\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"text\": \"Create the run\\nresult = pf.runs.create_or_update(run)\\nprint(result)\\n\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 301, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aa7fb66b-5547-4381-8445-5b889fbd750d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"670696330b3c61d1dd01ad6a0443001a2420bde7594a46160f3014ae731abb72\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"text\": \"Get a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet a run in CLI with JSON format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 233, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f49dcc8e-cb73-4d39-9315-4850fbf8574f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fd00d1e-3ff5-4e22-b9f3-6b9035a840f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b3bab73b36683da5ccd33b89ba1de7fe035ca591a43a5a2a2343c5ff007be74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"text\": \"Get and print the run\\nrun = pf.runs.get(name=\\\"\\\")\\nprint(run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate", "document_node": "{\"id_\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"056517ad-77d6-4567-bd42-784249e7099e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac8e842a7b5768c58167cad9416d5c3a46f31c4ca4b60615181298880853c1d0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"text\": \"Show run details\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run details with TABLE format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run details with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nfrom tabulate import tabulate\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9528494c-6fe6-435e-8311-638da383dc41\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f68960fd-78ed-4eb5-9c21-41c88a20f97c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"49293e272e5907c1688626b39b858b564c40e0a463d3bbf18bc4ae7e5851ac17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"text\": \"Get and print the run-details\\nrun_details = pf.runs.get_details(name=\\\"\\\")\\nprint(tabulate(details.head(max_results), headers=\\\"keys\\\", tablefmt=\\\"grid\\\"))\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 216, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json", "document_node": "{\"id_\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bafa7c22-c619-45f8-9c0d-e8fca3753d61\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cf1e0bec2347094aba059e8ccaea3ab4d987ec96d413c8f38bc4c038be5a274\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"text\": \"Show run metrics\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run show-metrics --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run metrics with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nimport json\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f36b0ba6-a935-419f-be60-64b86bfcd0af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::", "document_node": "{\"id_\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0acc4e77-5cef-41d4-8dd5-2d3ee287789a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305909b84d1072067287befc0fbbab8cd1a5653d9336a909d32a9bacc21cf2d3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"text\": \"Get and print the run-metrics\\nrun_details = pf.runs.get_metrics(name=\\\"\\\")\\nprint(json.dumps(metrics, indent=4))\\n```\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f1c9b212-965b-41d9-808f-a859cf2bcf64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f7b2bd2c6d767e2394c033cf46a8b2756409e7a2158e17b96e651c5c5ff13ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"text\": \"Visualize a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nVisualize run in browser.\\n\\n```bash\\npf run visualize --name \\n```\\n\\nA browser will open and display run outputs.\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nVisualize run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 286, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"83ebe531-d05f-4a18-b981-b032188e1a91\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::", "document_node": "{\"id_\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d47b6b-d1bb-4135-99c6-94e0587982d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2dd6d3b52ab30d4dda87b658da7a20d31661a20e90afadbfd6ba9ee96ada3ab0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"text\": \"Visualize the run\\nclient.runs.visualize(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \\\"visualize\\\" button on the top-right to visualize the local runs.\\n\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 341, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8cd0973b-621c-4ac5-ab7b-b761e9464968\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b8464057578b5ba3ccb4ef18e6269f22e0645221ea15c48138dba649196cbf3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"text\": \"List runs\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nList runs with JSON format.\\n\\n```bash\\npf run list\\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 215, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"689f1a61-021c-4d09-8f36-af664354d82a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::", "document_node": "{\"id_\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"62d58288-30a7-403a-ae78-e96ab797625a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8658b0ec41f3abc61402be75b54a6e1ae936ba8728c5ca85595757a37f92b1c8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"text\": \"list runs\\nruns = pf.runs.list()\\nprint(runs)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a882a5b2-ae70-4e60-8dec-44ab6aa5de17\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a99bfa43094dbfe48415d7cfa311835783debea8e004b3617c06d72e8a9f14e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"text\": \"Update a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run update --name --set display_name=new_display_name\\n```\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUpdate run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 269, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d622f6da-925e-4499-b2bc-e6c1b88a7764\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::", "document_node": "{\"id_\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"12a0c48d-32ba-458c-b98b-5ce685fbecd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f180fb15fb20882c0f33f6f5bcf0d9c267d70b9f7fd04436d7be890c0ae9fbb1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"text\": \"Get and print the run-metrics\\nrun = pf.runs.update(name=\\\"\\\", display_name=\\\"new_display_name\\\")\\nprint(run)\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 118, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0e1f5935-4d6c-42a3-9b09-3da53cf5dbc6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a226c721d83c0dc240f7149e90068679e1185971e0efc5cd3750d3688f7be6f4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"text\": \"Archive a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nArchive the run so it won't show in run list results.\\n\\n```bash\\npf run archive --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nArchive with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 251, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a01b3d2-3028-4464-8113-24d35a37127c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67df2602-4039-4fc6-b097-7d52f3ab80d3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3105c8e1a55b304a67ffac4d9723179527619bd43eb7fb30ba9e8be0057b447\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"text\": \"archive a run\\nclient.runs.archive(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 110, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"73b1be5c-105b-4991-a760-2cdc603ef913\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3515081b130b61184610302211a976ed86236d28529ea29de4e4062eeed2b6fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"text\": \"Restore a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nRestore an archived run so it can show in run list results.\\n\\n```bash\\npf run restore --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nRestore with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 257, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a6b2dca-a015-4f46-8e4c-8f420c172cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::", "document_node": "{\"id_\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52013f35-f7b9-4ead-99a3-ce4a40a7b0a0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9ff0a8fc8da582672ffd435dede081836c045e4c0bfad1bc35f00dd9ddd90b1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"text\": \"restore a run\\nclient.runs.restore(name=\\\"\\\")\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data.", "document_node": "{\"id_\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3f073cc8-dbd7-404a-b000-72bbff9558a2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b0fe45f7655286420820fe760ab00a37e2f5838b36fb118fc4ec5008b5f86060\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"text\": \"Process image in flow\\nPromptFlow defines a contract to represent image data.\", \"start_char_idx\": 2, \"end_char_idx\": 78, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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.", "document_node": "{\"id_\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5efdffd0-715a-49b8-b862-8c06fd69756a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9037551182ef68ff8573f23d59d51ab0122c07bd8b67195a7927188e9cdfc942\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"text\": \"Data class\\n`promptflow.contracts.multimedia.Image`\\nImage 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.\", \"start_char_idx\": 2, \"end_char_idx\": 338, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image.", "document_node": "{\"id_\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"be5c5590-cc2c-471d-9a1a-9d6ba6654b4a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9cfbe119c907229fa7c21d195971a302e523c3d4fd165529faabcbe96bc04923\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"text\": \"Data type in flow input\\nSet the type of flow input to `image` and promptflow will treat it as an image.\", \"start_char_idx\": 2, \"end_char_idx\": 105, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.", "document_node": "{\"id_\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbc9ce4b-d4c9-4821-9508-f9923f82ce76\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae851217d3af4fca9c7ef102cf46a9c6e94d378388c1ce5ec771632962af0989\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"text\": \"Reference image in prompt template\\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario.", "document_node": "{\"id_\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25990bbe-88b7-404e-b27b-dba038a55cab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c110c9ce51caed1fd070c097b462340c73e276069cb4bf96a739d73cba30a06e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"text\": \"Serialization/Deserialization\\nPromptflow uses a special dict to represent image.\\n`{\\\"data:image/;\\\": \\\"\\\"}`\\n\\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\\n- `` is the image serialized representation, there are 3 supported types:\\n\\n - url\\n\\n It can point to a public accessable web url. E.g.\\n\\n {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\\\"}\\n - base64\\n\\n It can be the base64 encoding of the image. E.g.\\n\\n {\\\"data:image/png;base64\\\": \\\"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\\\"}\\n\\n - path\\n\\n 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.\\n\\n {\\\"data:image/png;path\\\": \\\"./my-image.png\\\"}\\n\\nPlease note that `path` representation is not supported in Deployment scenario.\", \"start_char_idx\": 2, \"end_char_idx\": 1496, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```", "document_node": "{\"id_\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19d77c76-c58e-4192-90d8-c49cb217b41c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92124ab99bd3cf499149ae86dd3f01b6d954639f457778cad90613e5049ac45e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"text\": \"Batch Input data\\nBatch input data containing image can be of 2 formats:\\n1. 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.\\n ```json\\n {\\\"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\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/404.png\\\"}}\\n ```\\n2. 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:\\n ```\\n BatchInputFolder\\n |----input.jsonl\\n |----image1.png\\n |----image2.png\\n ```\\n Content of `input.jsonl`\\n ```json\\n {\\\"question\\\": \\\"How many colors are there in the image?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image1.png\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image2.png\\\"}}\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1318, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.", "document_node": "{\"id_\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13b2e87c-864e-48d7-a298-aa0405987f0e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"79570951aa402f8b5f4e3c3b8c54c819fcb929b1a4d6de04a5f0a9e9b9d305c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"text\": \"Quick Start\\n\\nThis guide will walk you through the fist step using of prompt flow code-first experience.\\n\\n**Prerequisite** - To make the most of this tutorial, you'll need:\\n\\n- Know how to program with Python :)\\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\\n\\n\\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\\n- Setup your python environment to run prompt flow\\n- Clone a sample flow & understand what's a flow\\n- Understand how to edit the flow using visual editor or yaml\\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.\", \"start_char_idx\": 2, \"end_char_idx\": 623, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash", "document_node": "{\"id_\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cccf3a8-00b2-4eea-925d-a6d165906fb2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"587ff0eab41d0c313506a1b48bba59f016d271767a7706df438d3b94b95d70f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"text\": \"Set up your dev environment\\n\\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\\n```bash\\nconda create --name pf python=3.9\\nconda activate pf\\n```\\n\\n2. Install `promptflow` and `promptflow-tools`.\\n```sh\\npip install promptflow promptflow-tools\\n```\\n\\n3. Check the installation.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 457, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```", "document_node": "{\"id_\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"38042954-c5f8-49e2-ad7a-8dd102cb9e4b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c85e37e9cb465346ff4d30d688adc584079228796b48af10d2c71ceb2335616\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"text\": \"should print promptflow version, e.g. \\\"0.1.0b3\\\"\\npf -v\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 59, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.", "document_node": "{\"id_\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2ba34ea4-ae4b-4056-b39f-5912c5a0fa64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a4f168922683539a819e5ea2cd78f563c61381d82a343207632856d7d161254\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"text\": \"Understand what's a flow\\n\\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```", "document_node": "{\"id_\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a05adf23-8e8c-45aa-b2af-53428b3c4ab3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb849308243c212f582c607ade0182cb365a92c8d404b5e5fb594118d2c07357\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"text\": \"Get the flow sample\\n\\nClone the sample repo and check flows in folder examples/flows.\\n\\n```bash\\ngit clone https://github.com/microsoft/promptflow.git\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79a0a064-1fcf-426a-8548-0cbbbe034e7c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44b92b2fd3a018be8e3053359e32a4423d9b6474f12db760ac37fe43281bbb32\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"text\": \"Understand flow directory\\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\\n\\n```bash\\ncd promptflow/examples/flows/standard/web-classification\\n```\\n\\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n\\n!flow_dir\\n\\nIn order to run this specific flow, you need to install its requirements first.\\n\\n```sh\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 946, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section.", "document_node": "{\"id_\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e7c432c7-346e-4c79-9d66-4944eaab2398\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"585f3bbe83645c654d93216d5a9b001b56b9ef008cf9693379ade54887ec1a42\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"text\": \"Understand the flow yaml\\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\\n\\n!flow_dag\\n\\nThis graph is rendered by VS Code extension which will be introduced in the next section.\", \"start_char_idx\": 2, \"end_char_idx\": 274, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode", "document_node": "{\"id_\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5d15c1f0-b882-4e0f-a58e-b1f1e5f9e228\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81e60ad7a846d99edaec0186774aa9ebb0110cb857c56d2328868b7e0fa46711\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"text\": \"Using VS Code Extension to visualize the flow\\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\\n\\n1. Prerequisites for VS Code extension.\\n - Install latest stable version of VS Code\\n - Install VS Code Python extension\\n\\n2. Install Prompt flow for VS Code extension\\n\\n3. Select python interpreter\\n\\n !vscode\\n !vscode\\n\\n\\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\\n !vscode\", \"start_char_idx\": 2, \"end_char_idx\": 497, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop and test your flow", "document_node": "{\"id_\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"720071dc-66cc-4ed4-9b59-173a870d30ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"714af737aa81a554f0df7e22fd1b79dcdd62a3fbdd515c290cad89305d189339\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"text\": \"Develop and test your flow\", \"start_char_idx\": 2, \"end_char_idx\": 28, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow.", "document_node": "{\"id_\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"488319e9-bfcd-4afc-a6dc-d9dc568d8222\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4280e9afda0f6e201ad8aa74bea5818f07bfee49457a332e90c7775a5b169aea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"text\": \"How to edit the flow\\n\\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\\ninputs:\\n url:\\n type: string\\n # change the default value of input url here\\n default: https://play.google.com/store/apps/details?id=com.twitter.android\\n...\\n```\\nSee more details of this topic in Develop a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 532, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection", "document_node": "{\"id_\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aba5bfb1-05ae-468c-be62-0a1a07c9d628\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4304344b05c441a6eb462f8c791c8d9a04408b2ff3ebeb03674bafdc081a41e3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"text\": \"Create necessary connections\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n\\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\\n\\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\\n\\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nFirstly we need a connection yaml file `connection.yaml`:\\n\\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: azure_open_ai\\napi_key: \\napi_base: \\napi_type: azure\\napi_version: \\n```\\n\\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: open_ai\\napi_key: \\\"\\\"\\norganization: \\\"\\\" # optional\\n```\\nThen we can use CLI command to create the connection.\\n\\n```sh\\npf connection create -f connection.yaml\\n```\\n\\nMore command details can be found in CLI reference.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nIn SDK, connections can be created and managed with `PFClient`.\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection\", \"start_char_idx\": 2, \"end_char_idx\": 1802, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections.", "document_node": "{\"id_\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c529519b-67a4-4ca2-82d6-88e7699c8200\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ed7487a25062f53a7b930269186ea7f0954012d2027cad99b2715db455927b9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"text\": \"PFClient can help manage your runs and connections.\\npf = PFClient()\\n\\ntry:\\n conn_name = \\\"open_ai_connection\\\"\\n conn = pf.connections.get(name=conn_name)\\n print(\\\"using existing connection\\\")\\nexcept:\\n connection = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=\\\"\\\",\\n api_base=\\\"\\\",\\n api_type=\\\"azure\\\",\\n api_version=\\\"\\\",\\n )\\n\\n # use this if you have an existing OpenAI account\\n # from promptflow.entities import OpenAIConnection\\n # connection = OpenAIConnection(\\n # name=conn_name,\\n # api_key=\\\"\\\",\\n # )\\n\\n conn = pf.connections.create_or_update(connection)\\n print(\\\"successfully created connection\\\")\\n\\nprint(conn)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n\\n\\n1. Click the promptflow icon to enter promptflow control panel\\n\\n !vsc_add_connection\\n\\n2. Create your connection.\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n\\n:::\\n\\n::::\\n\\nLearn more on more actions like delete connection in: Manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 1030, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name", "document_node": "{\"id_\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6e2090d9-29f8-4fce-90c8-b577f114642b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d5a26e33893b1d820d9201b77c301375b1bac6e1020962824c2eab192622768\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"text\": \"Test the flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\n\\nAssuming you are in working directory `promptflow/examples/flows/standard/`\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nChange the default input to the value you want to test.\\n\\n!q_0\\n\\n```sh\\npf flow test --flow web-classification # \\\"web-classification\\\" is the directory name\\n```\\n\\n!flow-test-output-cli\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow/node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient()\\n\\nflow_path = \\\"web-classification\\\" # \\\"web-classification\\\" is the directory name\", \"start_char_idx\": 2, \"end_char_idx\": 793, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")", "document_node": "{\"id_\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00d12aa2-2fba-4094-ba89-2b5100553cbf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2eb38f79e9511a30a686a54c0c9328d8f27b6533f88da23af285578f841f825c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"text\": \"Test flow\\nflow_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\", \\\"answer\\\": \\\"Channel\\\", \\\"evidence\\\": \\\"Url\\\"} # The inputs of the flow.\\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\", \"start_char_idx\": 2, \"end_char_idx\": 243, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow.", "document_node": "{\"id_\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c8481bc3-2fa6-4f9e-bbcf-50426bc810c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2f184b383bba7eaa575f03d802ddda93cb93c77c0c9aa1a1b18fc95da8c0b85c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"text\": \"Test node in the flow\\nnode_name = \\\"fetch_text_content_from_url\\\" # The node name in the flow.\\nnode_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\"} # The inputs of the node.\\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\n!Flow test outputs\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse the code lens action on the top of the yaml editor to trigger flow test\\n!dag_yaml_flow_test\\n\\n\\nClick the run flow button on the top of the visual editor to trigger flow test.\\n!visual_editor_flow_test\\n:::\\n\\n::::\\n\\nSee more details of this topic in Initialize and test a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 666, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.", "document_node": "{\"id_\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cd6ec34-2ff3-4ef6-a334-5325a792d6be\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f922b16e03e9c87176794882ed1ecdce02c8480f87787e537137efa790a4d7b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"text\": \"Next steps\\n\\nLearn more on how to:\\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\\n- Deploy a flow: how to deploy the flow as a web app.\\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\\n\\nAnd you can also check our examples, especially:\\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.\", \"start_char_idx\": 2, \"end_char_idx\": 1011, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow.", "document_node": "{\"id_\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"30c31860-92f8-47c4-8143-ed8a60bef754\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6456b9cffe36ddc31ab56d1934541df995350acf57169caef45954e5432ef45\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"text\": \"Use column mapping\\n\\nIn this document, we will introduce how to map inputs with column mapping when running a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 116, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column.", "document_node": "{\"id_\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f7f2a950-7877-4434-9ad9-91c026212720\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7463dd8b40dd4febe72041037b50febcc30e9f037aa9038b0930a4ce8aed2b8a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"text\": \"Column mapping introduction\\n\\nColumn mapping is a mapping from flow input name to specified values.\\nIf specified, the flow will be executed with provided value for specified inputs.\\nThe following types of values in column mapping are supported:\\n\\n- `${data.}` to reference from your test dataset.\\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\\n- `STATIC_VALUE` to create static value for all lines for specified column.\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow", "document_node": "{\"id_\": \"54218434-a846-4601-b725-da39ad450bac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3b22908e-2696-4ca0-ab38-15c436581212\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a65e49af872870820c0aa44888d4bec1d26b74f685c8f8f6b0e82e567dcaa2e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"text\": \"Flow inputs override priority\\n\\nFlow input values are overridden according to the following priority:\\n\\n\\\"specified in column mapping\\\" > \\\"default value\\\" > \\\"same name column in provided data\\\".\\n\\nFor example, if we have a flow with following inputs:\\n\\n```yaml\\ninputs:\\n input1:\\n type: string\\n default: \\\"default_val1\\\"\\n input2:\\n type: string\\n default: \\\"default_val2\\\"\\n input3:\\n type: string\\n input4:\\n type: string\\n...\\n```\\n\\nAnd the flow will return each inputs in outputs.\\n\\nWith the following data\\n\\n```json\\n{\\\"input3\\\": \\\"val3_in_data\\\", \\\"input4\\\": \\\"val4_in_data\\\"}\\n```\\n\\nAnd use the following YAML to run\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: path/to/flow\", \"start_char_idx\": 2, \"end_char_idx\": 718, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data", "document_node": "{\"id_\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85ecd312-c7aa-48ca-89cb-4d16ac411b2d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"924fbc0961d3d7d9de76a32f571c6ff05573670311e7c52c2288ea2aa20c43da\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"text\": \"my_flow has default value val2 for key2\\ndata: path/to/data\", \"start_char_idx\": 2, \"end_char_idx\": 60, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data.", "document_node": "{\"id_\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e74459fb-15d7-4a3d-ae93-101437c2bd75\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"698d6a2dc2865dae75ed798ff334ae53e59410e15e656c44e2cedc8fd117bb6b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"text\": \"my_data has column key3 with value val3\\ncolumn_mapping:\\n input1: \\\"val1_in_column_mapping\\\"\\n input3: ${data.input3}\\n```\\n\\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\\n\\n!column_mapping_details\\n\\n- Input \\\"input1\\\" has value \\\"val1_in_column_mapping\\\" since it's specified as constance in `column_mapping`.\\n- Input \\\"input2\\\" has value \\\"default_val2\\\" since it used default value in flow dag.\\n- Input \\\"input3\\\" has value \\\"val3_in_data\\\" since it's specified as data reference in `column_mapping`.\\n- Input \\\"input4\\\" has value \\\"val4_in_data\\\" since it has same name column in provided data.\", \"start_char_idx\": 2, \"end_char_idx\": 657, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.", "document_node": "{\"id_\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0745af7e-ec63-49a3-8913-9ce62b2de223\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27e034e72d909f547920ecb5bfea736f1ab1e439d826daa7d913ef75116ce89f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"text\": \"Set global configs\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\\n\\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.\", \"start_char_idx\": 2, \"end_char_idx\": 541, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```", "document_node": "{\"id_\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c304b195-516b-47e0-900a-fbad4496fde3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"88f72ac96bfaa0b271618b9c8f66bcc2de5d37e2a9e6d26e26bcc54921321ebd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"text\": \"Set config\\n```shell\\npf config set =\\n```\\nFor example:\\n```shell\\npf config set connection.provider=\\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 200, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```", "document_node": "{\"id_\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a73d8903-c78a-4ef8-8591-c5fe90893d80\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"264d76e266c35e6a139d87b304d20aaf5393fe43b13ece323df3ff74b235e613\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"text\": \"Show config\\nThe following command will get all configs and show them as json format:\\n```shell\\npf config show\\n```\\nAfter running the above config set command, show command will return the following result:\\n```json\\n{\\n \\\"connection\\\": {\\n \\\"provider\\\": \\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n }\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 358, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values.", "document_node": "{\"id_\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b56e2759-71a4-4872-aac3-59ee3a94a1f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1761fcf18f56ea37a32fff9d05bc05935c4d26f821644ab355085b65b7d1a304\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"text\": \"Supported configs\\nThe connection provider, default to \\\"local\\\". There are 3 possible provider values.\", \"start_char_idx\": 2, \"end_char_idx\": 102, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.", "document_node": "{\"id_\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e66b553-7359-4b97-afdc-8f38395dc946\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09bfdea661db0c1bc689c1372efa2a0820d2f05cbcaebd5f56fb3e0542f42848\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"text\": \"local\\nSet connection provider to local with `connection.provider=local`.\\n\\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.\", \"start_char_idx\": 2, \"end_char_idx\": 252, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::", "document_node": "{\"id_\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07f8fe3d-7333-4508-a442-6d98e99eef0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"91bd5a95942ac400dca084af0a6320249f0b2e643d08b786e6608b413a891d7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"text\": \"full azure machine learning workspace resource id\\nSet connection provider to a specific workspace with:\\n```\\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\n```\\n\\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\\n\\n:::{note}\\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 701, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.", "document_node": "{\"id_\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ca93927-7b13-4533-a448-2c9898d0a1c7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d2ac101a7dad86028f9b2b6cc6cb864cf7a91da7f23df582bc7a081651a09b19\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"text\": \"azureml\\nIn addition to the full resource id, you can designate the connection provider as \\\"azureml\\\" with `connection.provider=azureml`. In this case,\\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\\n\\nThe expected format of the config file is as follows:\\n```json\\n{\\n \\\"workspace_name\\\": \\\"\\\",\\n \\\"resource_group\\\": \\\"\\\",\\n \\\"subscription_id\\\": \\\"\\\"\\n}\\n\\n```\\n\\n> \\ud83d\\udca1 Tips\\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.\", \"start_char_idx\": 2, \"end_char_idx\": 763, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first.", "document_node": "{\"id_\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f4b19098-b649-49fb-ba3a-256c50177102\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f1d3fdba7aff41e34517c387405f43a643cc9bdc273d4608b5b84dabc5b8561e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"text\": \"Tune prompts using variants\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nTo better understand this part, please read Quick start and Run and evaluate a flow first.\", \"start_char_idx\": 2, \"end_char_idx\": 236, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence.", "document_node": "{\"id_\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"596d09b8-71b6-4d61-8033-f700c9e6e166\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f86c56fcebb73fc409192845f5a32aeb1bdc75a71e12db269ab09c95f37353ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"text\": \"What is variant and why should we care\\n\\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\\u2019s accuracy, diversity, or coherence.\", \"start_char_idx\": 2, \"end_char_idx\": 400, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\"", "document_node": "{\"id_\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"042639b8-edf6-4943-b574-68f37cb821e5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3891ba9e1032a54312c877719e8bc6185815a78c2077ee309de42674e31602f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"text\": \"Create a run with different variant node\\n\\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\\n\\n\\n```yaml\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n...\\nnode_variants:\\n summarize_text_content:\\n default_variant_id: variant_0\\n variants:\\n variant_0:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '128'\\n temperature: '0.2'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n variant_1:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content__variant_1.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '256'\\n temperature: '0.3'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n```\\n\\nYou can check the whole flow definition in flow.dag.yaml.\\n\\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \\nAssuming you are in working directory `/examples/flows/standard`\\n\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote we pass `--variant` to specify which variant of the node should be running.\\n\\n```sh\\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\\n```\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient() # get a promptflow client\\nflow = \\\"web-classification\\\"\\ndata= \\\"web-classification/data.jsonl\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 2080, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.", "document_node": "{\"id_\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8551fee8-9698-4a4e-a6c2-68ad0c5ad168\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4b1feb415aba95a00177594f96a7c35009b9cc3a06174dfdc0557050e30fdb0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"text\": \"use the variant1 of the summarize_text_content node.\\nvariant_run = pf.run(\\n flow=flow,\\n data=data,\\n variant=\\\"${summarize_text_content.variant_1}\\\", # use variant 1.\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n)\\n\\npf.stream(variant_run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n!img\\n!img\\n:::\\n\\n::::\\n\\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.\", \"start_char_idx\": 2, \"end_char_idx\": 465, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI", "document_node": "{\"id_\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98e9445a-c154-4bc3-9647-d54e3459349d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2fbfc42e24e9a1378f4fafdbd1334335ff983a743a84920e31777f80cf4f2921\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"text\": \"Next steps\\n\\nLearn more about:\\n- Run and evaluate a flow\\n- Deploy a flow\\n- Prompt flow in Azure AI\", \"start_char_idx\": 2, \"end_char_idx\": 99, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini index 763ff02423b..83629622b1c 100644 --- a/examples/test_data_gen/test_data_gen_local/config.ini +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -1,11 +1,11 @@ -should_skip_doc_split = True +; should_skip_doc_split = True documents_folder = "D:\proj\github\ms\promptflow\docs\how-to-guides" document_chunk_size = 1024 -# cspell: ignore luyao +; cspell: ignore luyao document_nodes_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" -# test data gen flow configs +; test data gen flow configs flow_folder = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow" flow_batch_run_size = 10 connection_name = "azure_open_ai_connection" -# test data output path +; test data output path test_data_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\test_data" diff --git a/examples/test_data_gen/test_data_gen_pipeline/config.ini b/examples/test_data_gen/test_data_gen_pipeline/config.ini index 1f79c5bd2ab..57105a693b3 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/config.ini +++ b/examples/test_data_gen/test_data_gen_pipeline/config.ini @@ -1,17 +1,17 @@ subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" resource_group = "promptflow" -# cspell: ignore yaopfeus +; cspell: ignore yaopfeus workspace_name = "yaopfeus" aml_cluster = "cpu-cluster" -# cspell: ignore luyao +; cspell: ignore luyao should_skip_doc_split = True documents_folder = "D:\proj\github\ms\promptflow\docs\how-to-guides" document_chunk_size = 1024 document_nodes_file_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" -# test data gen flow configs +; test data gen flow configs connection_name = "azure_open_ai_connection" flow_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow\flow.dag.yaml" -# Parallel run step configs +; Parallel run step configs prs_instance_count = 2 -prs_mini_batch_size = "100kb" +prs_mini_batch_size = "10kb" prs_max_concurrency_per_instance = 10 diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index d5c1b3815b5..1321f86afd0 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -21,22 +21,33 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str @dsl.pipeline( - non_pipeline_inputs=["flow_yml_path", "instance_count", "mini_batch_size", "max_concurrency_per_instance"] + non_pipeline_inputs=[ + "flow_yml_path", + "should_skip_doc_split", + "instance_count", + "mini_batch_size", + "max_concurrency_per_instance", + ] ) def test_data_gen_pipeline_with_flow( - data, + data_input, flow_yml_path: str, connection_name: str, # ?? should we override here? + should_skip_doc_split: bool, chunk_size=1024, instance_count=1, mini_batch_size="10kb", max_concurrency_per_instance=2, ): - document_node = document_split(documents_folder=data, chunk_size=chunk_size) - flow_component = load_component(flow_yml_path) + if should_skip_doc_split: + data = data_input + else: + document_node = document_split(documents_folder=data_input, chunk_size=chunk_size) + data = document_node.outputs.document_node_output + flow_component = load_component(flow_yml_path) flow_node = flow_component( - data=document_node.outputs.document_node_output, + data=data, text_chunk="${data.text_chunk}", connections={ "validate_and_generate_seed_question": {"connection": connection_name}, @@ -90,7 +101,10 @@ def test_data_gen_pipeline_with_flow( ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) - data_input = Input(path=args.documents_folder, type="uri_folder") + if args.should_skip_doc_split: + data_input = Input(path=args.document_nodes_file_path, type="uri_file") + else: + data_input = Input(path=args.documents_folder, type="uri_folder") prs_configs = { "instance_count": args.prs_instance_count, @@ -99,9 +113,10 @@ def test_data_gen_pipeline_with_flow( } pipeline_with_flow = test_data_gen_pipeline_with_flow( - data=data_input, + data_input=data_input, flow_yml_path=args.flow_path, connection_name=args.connection_name, + should_skip_doc_split=args.should_skip_doc_split, chunk_size=args.document_chunk_size, **prs_configs, ) From 4ae8a3e699c57462601b0525c65dc596de806f2e Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Fri, 19 Jan 2024 14:52:51 +0800 Subject: [PATCH 016/112] refine prompt --- .../construct_test_data_flow/generate_context_prompt.jinja2 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 index 5c403ce6307..85b6c711e86 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 @@ -4,10 +4,6 @@ If no relevant sentence based on the given context to answer the following quest While extracting candidate sentences you're not allowed to make any changes to sentences from given context. user: -question: What are the steps to tune prompts using variants? -context: Next steps -relevant sentences: - question:{{question}} context:{{context}} relevant sentences: \ No newline at end of file From 9af8d8c6e3a9210a3b80a52b149797e127dffd36 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Mon, 22 Jan 2024 14:48:59 +0800 Subject: [PATCH 017/112] update test data contract to add debug_info --- .../construct_test_data_flow/flow.dag.yaml | 30 +++++++++++-------- .../generate_debug_info.py | 9 ++++++ ...ate_answer.py => generate_ground_truth.py} | 7 +++-- ...a2 => generate_ground_truth_prompt.jinja2} | 2 +- .../test_data_gen_local/doc_split.py | 4 --- .../test_data_gen_local/run_test_data_gen.py | 14 ++++----- .../test_data_gen_pipeline/components.py | 2 +- .../run_test_data_gen_pipeline.py | 2 +- 8 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_debug_info.py rename examples/test_data_gen/construct_test_data_flow/{generate_answer.py => generate_ground_truth.py} (64%) rename examples/test_data_gen/construct_test_data_flow/{generate_answer_prompt.jinja2 => generate_ground_truth_prompt.jinja2} (93%) diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index 76635613e20..527f4999b9a 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -16,15 +16,12 @@ outputs: question: type: string reference: ${validate_and_generate_test_question.output.question} - answer: + ground_truth: type: string - reference: ${generate_answer.output} - context: + reference: ${generate_ground_truth.output} + debug_info: type: string - reference: ${validate_and_generate_context.output} - question_type: - type: string - reference: ${validate_and_generate_test_question.output.question_type} + reference: ${generate_debug_info.output} nodes: - name: reasoning_prompt type: prompt @@ -77,11 +74,11 @@ nodes: context: ${inputs.text_chunk} question: ${validate_and_generate_test_question.output.question} use_variants: false -- name: generate_answer_prompt +- name: generate_ground_truth_prompt type: prompt source: type: code - path: generate_answer_prompt.jinja2 + path: generate_ground_truth_prompt.jinja2 inputs: context: ${validate_and_generate_context.output} question: ${validate_and_generate_test_question.output} @@ -130,14 +127,23 @@ nodes: question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} use_variants: false -- name: generate_answer +- name: generate_ground_truth type: python source: type: code - path: generate_answer.py + path: generate_ground_truth.py inputs: connection: azure_openai_connection context: ${validate_and_generate_context.output} - generate_answer_prompt: ${generate_answer_prompt.output} + generate_ground_truth_prompt: ${generate_ground_truth_prompt.output} model: gpt-35-turbo use_variants: false +- name: generate_debug_info + type: python + source: + type: code + path: generate_debug_info.py + inputs: + question_type: ${validate_and_generate_test_question.output.question_type} + context: ${validate_and_generate_context.output} + text_trunk: ${inputs.text_chunk} diff --git a/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py b/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py new file mode 100644 index 00000000000..c333157540a --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py @@ -0,0 +1,9 @@ +from promptflow import tool + + +# The inputs section will change based on the arguments of the tool function, after you save the code +# Adding type to arguments and return value will help the system show the types properly +# Please update the function name/signature per need +@tool +def my_python_tool(question_type: str, context: str, text_trunk: str) -> dict: + return {"question_type": question_type, "context": context, "text_trunk": text_trunk} diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer.py b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py similarity index 64% rename from examples/test_data_gen/construct_test_data_flow/generate_answer.py rename to examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py index 13ec7a3e3af..39fdd207679 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_answer.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py @@ -8,7 +8,10 @@ @tool def generate_answer( - connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, context: str, generate_answer_prompt: str + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + context: str, + generate_ground_truth_prompt: str, ): """ Generates a answer based on the given prompts and context information. @@ -19,4 +22,4 @@ def generate_answer( if not context: return "" - return llm_call(connection, model, generate_answer_prompt) + return llm_call(connection, model, generate_ground_truth_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 similarity index 93% rename from examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 rename to examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 index 354cb63f293..245be1969b1 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 @@ -4,4 +4,4 @@ Answer the question using the information from the given context. user: question:{{question}} context:{{context}} -answer: \ No newline at end of file +answer: diff --git a/examples/test_data_gen/test_data_gen_local/doc_split.py b/examples/test_data_gen/test_data_gen_local/doc_split.py index c26d1205220..bb2840f97f9 100644 --- a/examples/test_data_gen/test_data_gen_local/doc_split.py +++ b/examples/test_data_gen/test_data_gen_local/doc_split.py @@ -47,8 +47,4 @@ def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, url parser.add_argument("--document_node_output", type=str, required=True) args = parser.parse_args() - print(f"documents_folder path: {args.documents_folder}") - print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") - print(f"document_node_output path: {args.document_node_output}") - split_doc(args.documents_folder, args.document_node_output, args.chunk_size) diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py index deff612c3af..ca583893831 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -35,7 +35,7 @@ def batch_run_flow( "validate_and_generate_seed_question": {"connection": connection_name}, "validate_and_generate_test_question": {"connection": connection_name}, "validate_and_generate_context": {"connection": connection_name}, - "generate_answer": {"connection": connection_name}, + "generate_ground_truth": {"connection": connection_name}, }, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, @@ -47,18 +47,14 @@ def batch_run_flow( def get_batch_run_output(pf: PFClient, base_run: Run): print(f"Start to get batch run {base_run} details.") # get run output - details = pf.get_details(base_run) + details = pf.get_details(base_run, all_results=True) # TODO: error handling like if the run failed because of rate limit. question = details["outputs.question"].tolist() - answer = details["outputs.answer"].tolist() - context = details["outputs.context"].tolist() - question_type = details["outputs.question_type"].tolist() - return [ - {"question": q, "answer": a, "context": c, "question_type": qt} - for q, a, c, qt in zip(question, answer, context, question_type) - ] + ground_truth = details["outputs.ground_truth"].tolist() + debug_info = details["outputs.debug_info"].tolist() + return [{"question": q, "ground_truth": g, "debug_info": d} for q, g, d in zip(question, ground_truth, debug_info)] def clean_data_and_save(test_data_set: list, test_data_output_path: str): diff --git a/examples/test_data_gen/test_data_gen_pipeline/components.py b/examples/test_data_gen/test_data_gen_pipeline/components.py index 085486fb84f..1613d505821 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/components.py +++ b/examples/test_data_gen/test_data_gen_pipeline/components.py @@ -86,7 +86,7 @@ def clean_test_data_set( # Filter out empty dictionaries # TODO: error handling filtered_data = [ - {"question": d["question"], "answer": d["answer"], "context": d["context"], "question_type": d["question_type"]} + {"question": d["question"], "ground_truth": d["ground_truth"], "debug_info": d["debug_info"]} for d in data if d and all(val for val in d.values()) ] diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index 1321f86afd0..de30a7e5577 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -53,7 +53,7 @@ def test_data_gen_pipeline_with_flow( "validate_and_generate_seed_question": {"connection": connection_name}, "validate_and_generate_test_question": {"connection": connection_name}, "validate_and_generate_context": {"connection": connection_name}, - "generate_answer": {"connection": connection_name}, + "generate_ground_truth": {"connection": connection_name}, }, ) From 8185af87b0afeebd11ce5724d74fa678fdb00e34 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Tue, 23 Jan 2024 15:31:51 +0800 Subject: [PATCH 018/112] update flow and fix line 0 cleaned error --- .../conditional_prompt.jinja2 | 18 ---- .../construct_test_data_flow/flow.dag.yaml | 74 ++++------------ .../generate_context_prompt.jinja2 | 9 -- .../generate_debug_info.py | 4 +- .../generate_ground_truth.py | 13 +-- .../generate_ground_truth_prompt.jinja2 | 4 +- .../reasoning_prompt.jinja2 | 25 ------ .../seed_question_prompt.jinja2 | 19 +++- .../construct_test_data_flow/utils.py | 88 +++++++++++++------ .../validate_and_generate_context.py | 31 ------- .../validate_and_generate_seed_question.py | 27 +++--- .../validate_and_generate_test_question.py | 48 +++++----- .../validate_context_prompt.jinja2 | 7 -- .../validate_question_prompt.jinja2 | 55 +++++++++++- .../validate_test_question.py | 36 ++++++++ .../validate_text_trunk_prompt.jinja2 | 34 +++++++ .../test_data_gen_local/run_test_data_gen.py | 8 +- .../test_data_gen_pipeline/components.py | 2 +- .../run_test_data_gen_pipeline.py | 2 +- 19 files changed, 281 insertions(+), 223 deletions(-) delete mode 100644 examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 delete mode 100644 examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 delete mode 100644 examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 delete mode 100644 examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py delete mode 100644 examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/validate_test_question.py create mode 100644 examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 deleted file mode 100644 index a7010f537b3..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 +++ /dev/null @@ -1,18 +0,0 @@ -system: -Rewrite the provided question to increase its complexity by introducing a conditional element. -The goal is to make the question more intricate by incorporating a scenario or condition that affects the context of the question. -Follow the rules given below while rewriting the question. - 1. The rewritten question should not be longer than 25 words. Use abbreviation wherever possible. - 2. The rewritten question must be reasonable and must be understood and responded by humans. - 3. The rewritten question must be fully answerable from information present context. - 4. phrases like 'provided context','according to the context?',etc are not allowed to appear in the question. - -user: -for example, -question: What are the general principles for designing prompts in LLMs? -Rewritten Question:how to apply prompt designing principles to improve LLMs performance in reasoning tasks - -question: {{question}} -CONTEXTS: -{{context}} -Rewritten Question: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index 527f4999b9a..befcbb17c94 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -5,17 +5,10 @@ inputs: text_chunk: type: string is_chat_input: false - default: >- - Adding a Tool Icon - - A tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package. - - - Adding a custom tool icon is optional. If you do not provide one, the system uses a default icon. outputs: question: type: string - reference: ${validate_and_generate_test_question.output.question} + reference: ${validate_test_question.output} ground_truth: type: string reference: ${generate_ground_truth.output} @@ -23,29 +16,11 @@ outputs: type: string reference: ${generate_debug_info.output} nodes: -- name: reasoning_prompt +- name: validate_text_trunk_prompt type: prompt source: type: code - path: reasoning_prompt.jinja2 - inputs: - context: ${inputs.text_chunk} - question: ${validate_and_generate_seed_question.output} - use_variants: false -- name: conditional_prompt - type: prompt - source: - type: code - path: conditional_prompt.jinja2 - inputs: - context: ${inputs.text_chunk} - question: ${validate_and_generate_seed_question.output} - use_variants: false -- name: validate_context_prompt - type: prompt - source: - type: code - path: validate_context_prompt.jinja2 + path: validate_text_trunk_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false @@ -65,23 +40,14 @@ nodes: inputs: context: ${inputs.text_chunk} use_variants: false -- name: generate_context_prompt - type: prompt - source: - type: code - path: generate_context_prompt.jinja2 - inputs: - context: ${inputs.text_chunk} - question: ${validate_and_generate_test_question.output.question} - use_variants: false - name: generate_ground_truth_prompt type: prompt source: type: code path: generate_ground_truth_prompt.jinja2 inputs: - context: ${validate_and_generate_context.output} - question: ${validate_and_generate_test_question.output} + context: ${inputs.text_chunk} + question: ${validate_test_question.output} use_variants: false - name: validate_and_generate_seed_question type: python @@ -89,10 +55,11 @@ nodes: type: code path: validate_and_generate_seed_question.py inputs: - connection: azure_openai_connection - model: gpt-35-turbo - validate_context_prompt: ${validate_context_prompt.output} + connection: + model: gpt-4 + validate_text_trunk_prompt: ${validate_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} + context: ${inputs.text_chunk} use_variants: false - name: validate_and_generate_test_question type: python @@ -100,10 +67,8 @@ nodes: type: code path: validate_and_generate_test_question.py inputs: - connection: azure_openai_connection - conditional_prompt: ${conditional_prompt.output} - model: gpt-35-turbo - reasoning_prompt: ${reasoning_prompt.output} + connection: + model: gpt-4 validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output} use_variants: false @@ -115,15 +80,14 @@ nodes: inputs: question: ${validate_and_generate_test_question.output.question} use_variants: false -- name: validate_and_generate_context +- name: validate_test_question type: python source: type: code - path: validate_and_generate_context.py + path: validate_test_question.py inputs: - connection: azure_openai_connection - generate_context_prompt: ${generate_context_prompt.output} - model: gpt-35-turbo + connection: + model: gpt-4 question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} use_variants: false @@ -133,10 +97,11 @@ nodes: type: code path: generate_ground_truth.py inputs: - connection: azure_openai_connection - context: ${validate_and_generate_context.output} + connection: + context: ${inputs.text_chunk} generate_ground_truth_prompt: ${generate_ground_truth_prompt.output} - model: gpt-35-turbo + model: gpt-4 + question: ${validate_test_question.output} use_variants: false - name: generate_debug_info type: python @@ -145,5 +110,4 @@ nodes: path: generate_debug_info.py inputs: question_type: ${validate_and_generate_test_question.output.question_type} - context: ${validate_and_generate_context.output} text_trunk: ${inputs.text_chunk} diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 deleted file mode 100644 index 85b6c711e86..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 +++ /dev/null @@ -1,9 +0,0 @@ -system: -Please extract relevant sentences from the provided context that can potentially help answer the following question. -If no relevant sentence based on the given context to answer the following question, only return empty string without any other words. -While extracting candidate sentences you're not allowed to make any changes to sentences from given context. - -user: -question:{{question}} -context:{{context}} -relevant sentences: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py b/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py index c333157540a..fa1d80f4937 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py @@ -5,5 +5,5 @@ # Adding type to arguments and return value will help the system show the types properly # Please update the function name/signature per need @tool -def my_python_tool(question_type: str, context: str, text_trunk: str) -> dict: - return {"question_type": question_type, "context": context, "text_trunk": text_trunk} +def my_python_tool(question_type: str, text_trunk: str) -> dict: + return {"question_type": question_type, "text_trunk": text_trunk} diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py index 39fdd207679..5e0d9f28486 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py @@ -7,19 +7,20 @@ @tool -def generate_answer( +def generate_ground_truth( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, + question: str, context: str, generate_ground_truth_prompt: str, ): """ - Generates a answer based on the given prompts and context information. + Generates a ground truth based on the given prompts and context information. Returns: - str: The generated answer. + str: The generated ground truth. """ - if not context: + if question and context: + return llm_call(connection, model, generate_ground_truth_prompt) + else: return "" - - return llm_call(connection, model, generate_ground_truth_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 index 245be1969b1..a92348f2f7e 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 @@ -1,7 +1,7 @@ system: -Answer the question using the information from the given context. +Provide the ground truth for the question using the information from the given context. user: question:{{question}} context:{{context}} -answer: +ground truth: diff --git a/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 deleted file mode 100644 index f53a8bc2e72..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 +++ /dev/null @@ -1,25 +0,0 @@ -system: -You are a prompt rewriter. You will be provided with a question and a long context.Your task to is to complicate the given question to improve the difficulty of answering. -You should do complicate the question by rewriting question into a multi-hop reasoning question based on the provided context. The question should require the reader to make multiple logical connections or inferences using the information available in given context. -Here are some strategies to create multi-hop questions: - - - Bridge related entities: Identify information that relates specific entities and frame question that can be answered only by analysing information of both entities. - - - Use Pronouns: identify (he, she, it, they) that refer to same entity or concepts in the context, and ask questions that would require the reader to figure out what pronouns refer to. - - - Refer to Specific Details: Mention specific details or facts from different parts of the context including tables, code, etc and ask how they are related. - - - Pose Hypothetical Scenarios: Present a hypothetical situation or scenario that requires combining different elements from the context to arrive at an answer. - -Rules to follow when rewriting question: -1. Ensure that the rewritten question can be answered entirely from the information present in the contexts. -2. Do not frame questions that contains more than 15 words. Use abbreviation wherever possible. -3. Make sure the question is clear and unambiguous. -4. phrases like 'based on the provided context','according to the context',etc are not allowed to appear in the question. - -user: -question: {{question}} -CONTEXTS: -{{context}} - -Multi-hop Reasoning Question: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 index 9278e3a35f3..3db02e1c380 100644 --- a/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 @@ -2,13 +2,26 @@ system: Your task is to formulate a question from given context satisfying the rules given below: 1.The question should make sense to humans even when read without the given context. 2.The question should be fully answered from the given context. -3.The question should be framed from a part of context that contains important information. It can also be from tables,code,etc. +3.The question should better be framed from the overall context, serving as a general question, rather than just framed from a part of context sentences. 4.The answer to the question should not contain any links. 5.The question should be of moderate difficulty. 6.The question must be reasonable and must be understood and responded by humans. 7.Do no use phrases like 'provided context',etc in the question 8.Avoid framing question using word "and" that can be decomposed into more than one question. -9.The question should not contain more than 10 words, make of use of abbreviation wherever possible. +9.The question should not contain more than 20 words, make of use of abbreviation wherever possible. user: -context: {{context}} \ No newline at end of file +Here are some examples: +context: +If you do not provide one, the system uses a default icon. +question: +What does the system use if you do not provide an icon? + +context: +Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon. +question: +What is the use of a tool icon when developing your own tool package? + +context: +{{context}} +question: diff --git a/examples/test_data_gen/construct_test_data_flow/utils.py b/examples/test_data_gen/construct_test_data_flow/utils.py index d3c65d89836..2ddf111a600 100644 --- a/examples/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/construct_test_data_flow/utils.py @@ -6,12 +6,21 @@ import openai from numpy.random import default_rng -from promptflow.connections import OpenAIConnection, AzureOpenAIConnection +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + + +class QuestionType: + SIMPLE = "simple" + REASONING = "reasoning" + CONDITIONAL = "conditional" + # MULTI_CONTEXT = "multi_context" def parse_chat(prompt): - messages = [{'role': role, 'content': content.strip()} for role, content in - re.findall(r'(system|user):(.*?)$', prompt, re.DOTALL)] + messages = [ + {"role": role, "content": content.strip()} + for role, content in re.findall(r"(system|user):(.*?)$", prompt, re.DOTALL) + ] return messages @@ -23,11 +32,13 @@ def llm_call(connection, model, prompt): def get_client_by_connection_type(connection): if isinstance(connection, AzureOpenAIConnection): - return openai.AzureOpenAI(api_key=connection.api_key, api_version=connection.api_version, - azure_endpoint=connection.api_base) + return openai.AzureOpenAI( + api_key=connection.api_key, api_version=connection.api_version, azure_endpoint=connection.api_base + ) elif isinstance(connection, OpenAIConnection): - return openai.OpenAI(api_key=connection.api_key, base_url=connection.base_url, - organization=connection.organization) + return openai.OpenAI( + api_key=connection.api_key, base_url=connection.base_url, organization=connection.organization + ) def get_question_type(testset_distribution) -> str: @@ -36,39 +47,64 @@ def get_question_type(testset_distribution) -> str: """ rng = default_rng() prob = rng.uniform(0, 1) - return next( - ( - key - for key in testset_distribution.keys() - if prob <= testset_distribution[key] - ), - "simple") + return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) + + +def is_valid_question(connection, model, prompt, question: str = None): + answer = llm_call(connection, model, prompt) + # Load the JSON string into a Python dictionary + data = json.loads(answer) + + # Extract the verdict and reason + verdict = data["verdict"].lower() + reason = data["reason"] + print(f"Is valid question: {verdict}\nReason: {reason}") + if verdict == "yes": + return True + elif verdict == "no": + return False + else: + print(f"Unexpected llm response to validate queston: {question}") + + return False -def is_valid_question(connection, model, prompt): - if not llm_call(connection, model, prompt): - print("Invalid question.") - - return True +def is_valid_text_trunk(answer: str, context: str = None): + data = json.loads(answer) + + # Extract the verdict and reason + verdict = data["verdict"].lower() + reason = data["reason"] + print(f"Is valid text trunk: {verdict}\nReason: {reason}") + if verdict == "yes": + return True + elif verdict == "no": + return False + else: + print(f"Unexpected llm response to validate text trunk: {context}") + + return False def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): testset_distribution = { - "simple": simple_ratio, - "reasoning": reasoning_ratio, - "conditional": conditional_ratio, + QuestionType.SIMPLE: simple_ratio, + QuestionType.REASONING: reasoning_ratio, + QuestionType.CONDITIONAL: conditional_ratio, } npt.assert_almost_equal(1, sum(testset_distribution.values()), err_msg="Sum of distribution should be 1") testset_distribution = dict(zip(testset_distribution.keys(), np.cumsum(list(testset_distribution.values())))) return testset_distribution -def generate_question(connection, model, question_type, seed_question, reasoning_prompt, conditional_prompt): - if question_type == "simple": +def generate_question( + connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None +): + if question_type == QuestionType.SIMPLE: return seed_question - elif question_type == "reasoning": + elif question_type == QuestionType.REASONING: return llm_call(connection, model, reasoning_prompt) - elif question_type == "conditional": + elif question_type == QuestionType.CONDITIONAL: return llm_call(connection, model, conditional_prompt) else: raise Exception("Invalid question type.") diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py deleted file mode 100644 index fe7d11725d8..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union - -from utils import is_valid_question, llm_call - -from promptflow import tool -from promptflow.connections import AzureOpenAIConnection, OpenAIConnection - - -@tool -def validate_and_generate_context( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - question_info: dict, - generate_context_prompt: str, - validate_question_prompt: str -): - """ - 1. Validates the given question. - 2. Generates a context based on the given prompts and question information. - - Returns: - str: The generated context. - """ - question = question_info["question"] - question_type = question_info["question_type"] - if not question or ( - question_type != "simple" and not is_valid_question(connection, model, validate_question_prompt) - ): - return "" - - return llm_call(connection, model, generate_context_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py index 9eaa28c9429..887f0fe0244 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import llm_call +from utils import is_valid_text_trunk, llm_call from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -8,21 +8,22 @@ @tool def validate_and_generate_seed_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - validate_context_prompt: str, - seed_question_prompt: str + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + validate_text_trunk_prompt: str, + seed_question_prompt: str, + context: str = None, ): """ - 1. Validates the given text chunk. - 2. Generates a seed question based on the given prompts. - - Returns: - str: The generated seed question. + 1. Validates the given text chunk. + 2. Generates a seed question based on the given prompts. + + Returns: + str: The generated seed question. """ - is_valid = llm_call(connection, model, validate_context_prompt) - if not is_valid: - print("invalid text chunk.") + answer = llm_call(connection, model, validate_text_trunk_prompt) + if not is_valid_text_trunk(answer, context): + print("Skipping generating seed question due to invalid text chunk.") return "" seed_question = llm_call(connection, model, seed_question_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py index ce1c24fcccc..482d3e11bdf 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import generate_question, get_question_type, is_valid_question, validate_distribution +from utils import QuestionType, is_valid_question from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -8,29 +8,37 @@ @tool def validate_and_generate_test_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - seed_question: str, - reasoning_prompt: str, - conditional_prompt: str, - validate_seed_question_prompt: str, - simple_ratio: float = 0.5, - reasoning_ratio: float = 0.25, - conditional_ratio: float = 0.25 + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + seed_question: str, + # reasoning_prompt: str, + # conditional_prompt: str, + validate_seed_question_prompt: str, + # simple_ratio: float = 0.5, + # reasoning_ratio: float = 0.25, + # conditional_ratio: float = 0.25 ): """ - 1. Validates the given seed question. - 2. Generates a test question based on the given prompts and distribution ratios. - - Returns: - dict: The generated test question and its type. + 1. Validates the given seed question. + 2. Generates a test question based on the given prompts and distribution ratios. + + Returns: + dict: The generated test question and its type. """ - if not seed_question or not is_valid_question(connection, model, validate_seed_question_prompt): + # text trunk is not valid, seed question not generated. + if not seed_question: + return {"question": "", "question_type": ""} + + is_valid_seed_question = is_valid_question(connection, model, validate_seed_question_prompt, seed_question) + if not is_valid_seed_question: + print(f"Invalid seed question: {seed_question}") return {"question": "", "question_type": ""} - testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) + # TODO: add multi_context prompt (p3) + # TODO: add reasoning prompt and conditional prompt (p4) + # testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) - question_type = get_question_type(testset_distribution) - question = generate_question(connection, model, question_type, seed_question, reasoning_prompt, conditional_prompt) + # question_type = get_question_type(testset_distribution) + # question = generate_question(connection, model, question_type, seed_question) - return {"question": question, "question_type": question_type} + return {"question": seed_question, "question_type": QuestionType.SIMPLE} diff --git a/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 deleted file mode 100644 index e732dcad982..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 +++ /dev/null @@ -1,7 +0,0 @@ -system: -Evaluate the provided context and return only true or false based on the following criteria: -1. Award a high score to context that thoroughly delves into and explains concepts. -2. Assign a lower score to context that contains excessive references, acknowledgments, external links, personal information, or other non-essential elements. - -user: -context: {{context}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 index 4a9eb6ce65c..eb23fa247f6 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 @@ -1,5 +1,56 @@ system: -Determine if the given question can be clearly understood even when presented without any additional context. Only return true or false. +Determine if the given question can be clearly understood and give the reason. Output a json format. user: -question:{{question}} \ No newline at end of file +Here are some examples: +question: What is the discovery about space? +answer: +{ + "reason":"The question is too vague and does not specify which discovery about space it is referring to." + "verdict":"no" +} + +question: What caused the Great Depression? +answer: +{ + "reason":"The question is specific and refers to a well-known historical economic event, making it clear and answerable.", + "verdict":"yes" +} + +question: What is the keyword that best describes the paper's focus in natural language understanding tasks? +answer: +{ + "reason": "The question mentions a 'paper' in it without referring it's name which makes it unclear without it", + "verdict": "no" +} + +question: Who wrote 'Romeo and Juliet'? +answer: +{ + "reason": "The question is clear and refers to a specific work by name therefore it is clear", + "verdict": "yes" +} + +question: What did the study mention? +answer: +{ + "reason": "The question is vague and does not specify which study it is referring to", + "verdict": "no" +} + +question: What is the focus of the REPLUG paper? +answer: +{ + "reason": "The question refers to a specific work by it's name hence can be understood", + "verdict": "yes" +} + +question: What is the purpose of the reward-driven stage in the training process? +answer: +{ + "reason": "The question lacks specific context regarding the type of training process, making it potentially ambiguous and open to multiple interpretations.", + "verdict": "no" +} + +question:{{question}} +answer: diff --git a/examples/test_data_gen/construct_test_data_flow/validate_test_question.py b/examples/test_data_gen/construct_test_data_flow/validate_test_question.py new file mode 100644 index 00000000000..4ade6359ab0 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/validate_test_question.py @@ -0,0 +1,36 @@ +from typing import Union + +from utils import QuestionType, is_valid_question + +from promptflow import tool +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + + +@tool +def validate_test_question( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + question_info: dict, + # generate_context_prompt: str, + validate_question_prompt: str, +): + """ + 1. Validates the given question. + 2. Generates a context based on the given prompts and question information. + + Returns: + str: The generated context. + """ + question = question_info["question"] + question_type = question_info["question_type"] + if not question: + return "" + # if question type is simple, the question is validated, no need to validate again. + if question_type == QuestionType.SIMPLE: + return question + is_valid_test_question = is_valid_question(connection, model, validate_question_prompt, question) + if not is_valid_test_question: + print(f"Invalid test question: {question}") + return "" + else: + return question diff --git a/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 new file mode 100644 index 00000000000..4cbbd852e78 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 @@ -0,0 +1,34 @@ +system: +Given a context, evaluate the provided context and determine if the context has information worthy of framing a question. +Give a verdict "yes" or "no" and give the reason for your verdict in a json format. +Verdict "yes" or "no" based on the following criteria: +1. Verdict "yes" if: + (1) context thoroughly delves into and explains concepts. + (2) context is complete and does not require additional information. + (3) context has information worthy of framing a question. +2. Verdict "no" if: + (1) context contains excessive references, acknowledgments, personal information, or other non-essential elements. + (2) context contains only punctuations or massive code snippet. + (3) context that is shorter than five words. + +user: +Here are some examples: +context: +Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time. +answer: +{ + "verdict": "yes", + "reason": "The context contains information worthy of framing a question." +} + +context: +Next step\n- Open the provided examples. +answer: +{ + "verdict": "no", + "reason": "The context lacks information about the previous steps and in next step it mentions a 'provided' example without referring it's name which makes it unclear without it" +} + +context: +{{context}} +answer: diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py index ca583893831..692419b421c 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -34,7 +34,7 @@ def batch_run_flow( connections={ "validate_and_generate_seed_question": {"connection": connection_name}, "validate_and_generate_test_question": {"connection": connection_name}, - "validate_and_generate_context": {"connection": connection_name}, + "validate_test_question": {"connection": connection_name}, "generate_ground_truth": {"connection": connection_name}, }, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, @@ -58,7 +58,11 @@ def get_batch_run_output(pf: PFClient, base_run: Run): def clean_data_and_save(test_data_set: list, test_data_output_path: str): - cleaned_data = [test_data for test_data in test_data_set if test_data and all(val for val in test_data.values())] + cleaned_data = [ + test_data + for test_data in test_data_set + if (test_data and all(val for key, val in test_data.items() if key.lower() != "line_number")) + ] jsonl_str = "\n".join(map(json.dumps, cleaned_data)) diff --git a/examples/test_data_gen/test_data_gen_pipeline/components.py b/examples/test_data_gen/test_data_gen_pipeline/components.py index 1613d505821..988546d31e4 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/components.py +++ b/examples/test_data_gen/test_data_gen_pipeline/components.py @@ -88,7 +88,7 @@ def clean_test_data_set( filtered_data = [ {"question": d["question"], "ground_truth": d["ground_truth"], "debug_info": d["debug_info"]} for d in data - if d and all(val for val in d.values()) + if (d and all(val for key, val in d.items() if key.lower() != "line_number")) ] jsonl_str = "" diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index de30a7e5577..b8db29a837b 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -52,7 +52,7 @@ def test_data_gen_pipeline_with_flow( connections={ "validate_and_generate_seed_question": {"connection": connection_name}, "validate_and_generate_test_question": {"connection": connection_name}, - "validate_and_generate_context": {"connection": connection_name}, + "validate_test_question": {"connection": connection_name}, "generate_ground_truth": {"connection": connection_name}, }, ) From 3641b42fb4ce82a29fd9693c1521f1ffd7e77569 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Tue, 23 Jan 2024 15:44:06 +0800 Subject: [PATCH 019/112] update ground truth prompt --- .../generate_ground_truth_prompt.jinja2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 index a92348f2f7e..a57e90e6809 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 @@ -1,5 +1,9 @@ system: -Provide the ground truth for the question using the information from the given context. +Provide the ground truth for the question using the information from the given context based on the following criteria: +1. The ground truth is correct and complete. +2. The ground truth is derived from the given context. +3. The ground truth can totally answer the question. +4. The ground truth should not use the words like "in the context". The ground truth should be enough to answer the question without the context. user: question:{{question}} From eed9f55e9fbf3be317b6ea55933e78e50a60f7b9 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Thu, 25 Jan 2024 14:59:48 +0800 Subject: [PATCH 020/112] update flow --- .../construct_test_data_flow/flow.dag.yaml | 19 +++++- .../generate_ground_truth_prompt.jinja2 | 1 + .../construct_test_data_flow/utils.py | 67 +++++++++++-------- .../validate_and_generate_seed_question.py | 3 +- .../validate_ground_truth.py | 33 +++++++++ .../validate_ground_truth_prompt.jinja2 | 41 ++++++++++++ .../validate_question_prompt.jinja2 | 3 +- .../validate_text_trunk_prompt.jinja2 | 8 +-- .../test_data_gen_local/run_test_data_gen.py | 1 + .../run_test_data_gen_pipeline.py | 1 + 10 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py create mode 100644 examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index befcbb17c94..1cdc9a65037 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -11,7 +11,7 @@ outputs: reference: ${validate_test_question.output} ground_truth: type: string - reference: ${generate_ground_truth.output} + reference: ${validate_ground_truth.output} debug_info: type: string reference: ${generate_debug_info.output} @@ -111,3 +111,20 @@ nodes: inputs: question_type: ${validate_and_generate_test_question.output.question_type} text_trunk: ${inputs.text_chunk} +- name: validate_ground_truth_prompt + type: prompt + source: + type: code + path: validate_ground_truth_prompt.jinja2 + inputs: + ground_truth: ${generate_ground_truth.output} +- name: validate_ground_truth + type: python + source: + type: code + path: validate_ground_truth.py + inputs: + connection: + model: gpt-4 + ground_truth: ${generate_ground_truth.output} + validate_ground_truth_prompt: ${validate_ground_truth_prompt.output} diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 index a57e90e6809..e45fad222d7 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 @@ -4,6 +4,7 @@ Provide the ground truth for the question using the information from the given c 2. The ground truth is derived from the given context. 3. The ground truth can totally answer the question. 4. The ground truth should not use the words like "in the context". The ground truth should be enough to answer the question without the context. +5. If the ground truth for the question cannot be generated from the given context, just return empty string. user: question:{{question}} diff --git a/examples/test_data_gen/construct_test_data_flow/utils.py b/examples/test_data_gen/construct_test_data_flow/utils.py index 2ddf111a600..ebcdb1a631e 100644 --- a/examples/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/construct_test_data_flow/utils.py @@ -16,6 +16,12 @@ class QuestionType: # MULTI_CONTEXT = "multi_context" +class ValidateObj: + QUESTION = "question" + TEXT_TRUNK = "text_trunk" + GROUNDTRUTH = "ground_truth" + + def parse_chat(prompt): messages = [ {"role": role, "content": content.strip()} @@ -50,38 +56,45 @@ def get_question_type(testset_distribution) -> str: return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) -def is_valid_question(connection, model, prompt, question: str = None): +def is_valid_ground_truth(connection, model, prompt, ground_truth: str): answer = llm_call(connection, model, prompt) - # Load the JSON string into a Python dictionary - data = json.loads(answer) - - # Extract the verdict and reason - verdict = data["verdict"].lower() - reason = data["reason"] - print(f"Is valid question: {verdict}\nReason: {reason}") - if verdict == "yes": - return True - elif verdict == "no": - return False - else: - print(f"Unexpected llm response to validate queston: {question}") + return retrieve_verdict_and_print_reason( + answer=answer, validate_obj_name=ValidateObj.GROUNDTRUTH, validate_obj=ground_truth + ) - return False +def is_valid_question(connection, model, prompt, question: str): + answer = llm_call(connection, model, prompt) + return retrieve_verdict_and_print_reason( + answer=answer, validate_obj_name=ValidateObj.QUESTION, validate_obj=question + ) -def is_valid_text_trunk(answer: str, context: str = None): - data = json.loads(answer) - # Extract the verdict and reason - verdict = data["verdict"].lower() - reason = data["reason"] - print(f"Is valid text trunk: {verdict}\nReason: {reason}") - if verdict == "yes": - return True - elif verdict == "no": - return False - else: - print(f"Unexpected llm response to validate text trunk: {context}") +def is_valid_text_trunk(connection, model, prompt, context: str): + answer = llm_call(connection, model, prompt) + return retrieve_verdict_and_print_reason( + answer=answer, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context + ) + + +def retrieve_verdict_and_print_reason(answer: str, validate_obj_name: str, validate_obj: str) -> bool: + try: + data = json.loads(answer) + except json.decoder.JSONDecodeError: + print("llm failed to return the verdict and reason in correct json format.") + data = None + + if data and isinstance(data, dict) and "verdict" in data and "reason" in data: + # Extract the verdict and reason + verdict = data["verdict"].lower() + reason = data["reason"] + print(f"Is valid {validate_obj_name}: {verdict}\nReason: {reason}") + if verdict == "yes": + return True + elif verdict == "no": + return False + else: + print(f"Unexpected llm response to validate {validate_obj_name}: {validate_obj}") return False diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py index 887f0fe0244..15752deb25a 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py @@ -21,8 +21,7 @@ def validate_and_generate_seed_question( Returns: str: The generated seed question. """ - answer = llm_call(connection, model, validate_text_trunk_prompt) - if not is_valid_text_trunk(answer, context): + if not is_valid_text_trunk(connection, model, validate_text_trunk_prompt, context): print("Skipping generating seed question due to invalid text chunk.") return "" diff --git a/examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py b/examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py new file mode 100644 index 00000000000..0d4ed665e7e --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py @@ -0,0 +1,33 @@ +from typing import Union + +from utils import is_valid_ground_truth + +from promptflow import tool +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + + +# The inputs section will change based on the arguments of the tool function, after you save the code +# Adding type to arguments and return value will help the system show the types properly +# Please update the function name/signature per need +@tool +def validate_ground_truth( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + ground_truth: str, + validate_ground_truth_prompt: str, +) -> str: + """ + 1. Validates the given ground truth. + + Returns: + str: The validated ground truth. + """ + if not ground_truth: + return "" + + is_valid_gt = is_valid_ground_truth(connection, model, validate_ground_truth_prompt, ground_truth) + if not is_valid_gt: + print(f"Invalid ground truth: {ground_truth}") + return "" + else: + return ground_truth diff --git a/examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 new file mode 100644 index 00000000000..41cef6ae20b --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 @@ -0,0 +1,41 @@ +system: +Given a ground truth, verdict if the provided ground truth is valid and provide the reason in valid json format. +The ground truth is not valid if the ground truth suggests that the context does not provide information or indicates uncertainty (such as 'I don't know'), it is deemed invalid. For any other case, the ground truth is considered valid. + +user: +Output a json format with the reason and verdict. +Here are some examples: +ground_truth: +The steps to build and install your tool package for use in VS Code extension are not provided in the context. +answer: +{ + "reason":"The ground truth is invalid because it states that the context does not provide the necessary steps.", + "verdict":"no" +} + +ground_truth: +The context does not provide specific information on what the possible provider values are in supported configs for a connection provider. +answer: +{ + "reason":"The ground truth is invalid as it indicates that the context lacks specific information.", + "verdict":"no" +} + +ground_truth: +I don't know. +answer: +{ + "reason":"The ground_truth is invalid because it conveys don't know.", + "verdict":"no" +} + +ground_truth: +The two essential components of an activate config in a node flow are `activate.when` and `activate.is`. +answer: +{ + "reason":"The ground_truth is valid because it is clear and true.", + "verdict":"yes" +} + +ground_truth:{{ground_truth}} +answer: diff --git a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 index eb23fa247f6..7750f97ea56 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 @@ -1,7 +1,8 @@ system: -Determine if the given question can be clearly understood and give the reason. Output a json format. +Determine if the given question can be clearly understood and give the reason. Output a valid json with reason and verdict. user: +Output a valid json with reason and verdict. Here are some examples: question: What is the discovery about space? answer: diff --git a/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 index 4cbbd852e78..ddd11ba3b8f 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 @@ -1,7 +1,6 @@ system: -Given a context, evaluate the provided context and determine if the context has information worthy of framing a question. -Give a verdict "yes" or "no" and give the reason for your verdict in a json format. -Verdict "yes" or "no" based on the following criteria: +Given a context, verdict if the provided context has information worthy of framing a question and give the reason. Output a json format with the reason and verdict. +The verdict can be either "yes" or "no", following these guidelines: 1. Verdict "yes" if: (1) context thoroughly delves into and explains concepts. (2) context is complete and does not require additional information. @@ -12,6 +11,7 @@ Verdict "yes" or "no" based on the following criteria: (3) context that is shorter than five words. user: +Output a json format with both the reason and verdict. Here are some examples: context: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time. @@ -26,7 +26,7 @@ Next step\n- Open the provided examples. answer: { "verdict": "no", - "reason": "The context lacks information about the previous steps and in next step it mentions a 'provided' example without referring it's name which makes it unclear without it" + "reason": "The context lacks information about the provided example and next steps of what." } context: diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py index 692419b421c..5517115bdbd 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -36,6 +36,7 @@ def batch_run_flow( "validate_and_generate_test_question": {"connection": connection_name}, "validate_test_question": {"connection": connection_name}, "generate_ground_truth": {"connection": connection_name}, + "validate_ground_truth": {"connection": connection_name}, }, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index b8db29a837b..3093200921e 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -54,6 +54,7 @@ def test_data_gen_pipeline_with_flow( "validate_and_generate_test_question": {"connection": connection_name}, "validate_test_question": {"connection": connection_name}, "generate_ground_truth": {"connection": connection_name}, + "validate_ground_truth": {"connection": connection_name}, }, ) From 86dc787c1ef0508edc3fabf32db60ed1d1bce4b2 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:55:43 +0800 Subject: [PATCH 021/112] Refactor code (#1860) # Description Refactor code # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- .../requirements.txt => src/__init__.py} | 0 .../construct_test_data_flow/flow.dag.yaml | 0 .../generate_debug_info.py | 0 .../generate_ground_truth.py | 0 .../generate_ground_truth_prompt.jinja2 | 0 .../construct_test_data_flow/requirements.txt | 0 .../seed_question_prompt.jinja2 | 0 .../construct_test_data_flow/utils.py | 40 +++--- .../validate_and_generate_seed_question.py | 0 .../validate_and_generate_test_question.py | 0 .../validate_ground_truth.py | 0 .../validate_ground_truth_prompt.jinja2 | 0 .../validate_question_prompt.jinja2 | 0 .../validate_test_question.py | 0 .../validate_text_trunk_prompt.jinja2 | 0 .../{ => src}/document-nodes-test.jsonl | 0 .../src/test_data_gen_local/__init__.py | 0 .../{ => src}/test_data_gen_local/config.ini | 0 .../test_data_gen_local/requirements.txt | 0 .../test_data_gen_local/run_test_data_gen.py | 69 +++++----- .../src/test_data_gen_pipeline/__init__.py | 0 .../test_data_gen_pipeline/config.ini | 2 +- .../test_data_gen_pipeline/requirements.txt | 0 .../run_test_data_gen_pipeline.py | 112 ++++++++++++++++ examples/test_data_gen/src/utils/__init__.py | 0 examples/test_data_gen/src/utils/common.py | 51 +++++++ .../test_data_gen/src/utils/components.py | 64 +++++++++ examples/test_data_gen/src/utils/constants.py | 30 +++++ .../test_data_gen_local/constants.py | 2 - .../test_data_gen_local/doc_split.py | 50 ------- .../test_data_gen_pipeline/components.py | 101 -------------- .../test_data_gen_pipeline/conda.yml | 9 -- .../test_data_gen_pipeline/constants.py | 2 - .../run_test_data_gen_pipeline.py | 126 ------------------ 34 files changed, 304 insertions(+), 354 deletions(-) rename examples/test_data_gen/{construct_test_data_flow/requirements.txt => src/__init__.py} (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/flow.dag.yaml (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/generate_debug_info.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/generate_ground_truth.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/generate_ground_truth_prompt.jinja2 (100%) create mode 100644 examples/test_data_gen/src/construct_test_data_flow/requirements.txt rename examples/test_data_gen/{ => src}/construct_test_data_flow/seed_question_prompt.jinja2 (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/utils.py (76%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_and_generate_seed_question.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_and_generate_test_question.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_ground_truth.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_ground_truth_prompt.jinja2 (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_question_prompt.jinja2 (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_test_question.py (100%) rename examples/test_data_gen/{ => src}/construct_test_data_flow/validate_text_trunk_prompt.jinja2 (100%) rename examples/test_data_gen/{ => src}/document-nodes-test.jsonl (100%) create mode 100644 examples/test_data_gen/src/test_data_gen_local/__init__.py rename examples/test_data_gen/{ => src}/test_data_gen_local/config.ini (100%) rename examples/test_data_gen/{ => src}/test_data_gen_local/requirements.txt (100%) rename examples/test_data_gen/{ => src}/test_data_gen_local/run_test_data_gen.py (65%) create mode 100644 examples/test_data_gen/src/test_data_gen_pipeline/__init__.py rename examples/test_data_gen/{ => src}/test_data_gen_pipeline/config.ini (94%) rename examples/test_data_gen/{ => src}/test_data_gen_pipeline/requirements.txt (100%) create mode 100644 examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py create mode 100644 examples/test_data_gen/src/utils/__init__.py create mode 100644 examples/test_data_gen/src/utils/common.py create mode 100644 examples/test_data_gen/src/utils/components.py create mode 100644 examples/test_data_gen/src/utils/constants.py delete mode 100644 examples/test_data_gen/test_data_gen_local/constants.py delete mode 100644 examples/test_data_gen/test_data_gen_local/doc_split.py delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/components.py delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/conda.yml delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/constants.py delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py diff --git a/examples/test_data_gen/construct_test_data_flow/requirements.txt b/examples/test_data_gen/src/__init__.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/requirements.txt rename to examples/test_data_gen/src/__init__.py diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/flow.dag.yaml rename to examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml diff --git a/examples/test_data_gen/construct_test_data_flow/generate_debug_info.py b/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/generate_debug_info.py rename to examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py b/examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/generate_ground_truth.py rename to examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth.py diff --git a/examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 rename to examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth_prompt.jinja2 diff --git a/examples/test_data_gen/src/construct_test_data_flow/requirements.txt b/examples/test_data_gen/src/construct_test_data_flow/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/seed_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 rename to examples/test_data_gen/src/construct_test_data_flow/seed_question_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/utils.py b/examples/test_data_gen/src/construct_test_data_flow/utils.py similarity index 76% rename from examples/test_data_gen/construct_test_data_flow/utils.py rename to examples/test_data_gen/src/construct_test_data_flow/utils.py index ebcdb1a631e..a2d5d934407 100644 --- a/examples/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/src/construct_test_data_flow/utils.py @@ -1,10 +1,10 @@ import json -import re import numpy as np import numpy.testing as npt -import openai from numpy.random import default_rng +from promptflow.tools.aoai import chat as aoai_chat +from promptflow.tools.openai import chat as openai_chat from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -22,28 +22,20 @@ class ValidateObj: GROUNDTRUTH = "ground_truth" -def parse_chat(prompt): - messages = [ - {"role": role, "content": content.strip()} - for role, content in re.findall(r"(system|user):(.*?)$", prompt, re.DOTALL) - ] - return messages - - -def llm_call(connection, model, prompt): - client = get_client_by_connection_type(connection) - messages = parse_chat(prompt) - return client.chat.completions.create(model=model, messages=messages).choices[0].message.content - - -def get_client_by_connection_type(connection): +def llm_call(connection, model, prompt, response_format="text"): if isinstance(connection, AzureOpenAIConnection): - return openai.AzureOpenAI( - api_key=connection.api_key, api_version=connection.api_version, azure_endpoint=connection.api_base + return aoai_chat( + connection=connection, + prompt=prompt, + deployment_name=model, + response_format={"type": response_format} ) elif isinstance(connection, OpenAIConnection): - return openai.OpenAI( - api_key=connection.api_key, base_url=connection.base_url, organization=connection.organization + return openai_chat( + connection=connection, + prompt=prompt, + model=model, + response_format={"type": response_format} ) @@ -64,14 +56,14 @@ def is_valid_ground_truth(connection, model, prompt, ground_truth: str): def is_valid_question(connection, model, prompt, question: str): - answer = llm_call(connection, model, prompt) + answer = llm_call(connection, model, prompt, "json_object") return retrieve_verdict_and_print_reason( answer=answer, validate_obj_name=ValidateObj.QUESTION, validate_obj=question ) def is_valid_text_trunk(connection, model, prompt, context: str): - answer = llm_call(connection, model, prompt) + answer = llm_call(connection, model, prompt, "json_object") return retrieve_verdict_and_print_reason( answer=answer, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context ) @@ -111,7 +103,7 @@ def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): def generate_question( - connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None + connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None ): if question_type == QuestionType.SIMPLE: return seed_question diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py rename to examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py diff --git a/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py rename to examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py diff --git a/examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py b/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_ground_truth.py rename to examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py diff --git a/examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 rename to examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/validate_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 rename to examples/test_data_gen/src/construct_test_data_flow/validate_question_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/validate_test_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_test_question.py rename to examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py diff --git a/examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 rename to examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 diff --git a/examples/test_data_gen/document-nodes-test.jsonl b/examples/test_data_gen/src/document-nodes-test.jsonl similarity index 100% rename from examples/test_data_gen/document-nodes-test.jsonl rename to examples/test_data_gen/src/document-nodes-test.jsonl diff --git a/examples/test_data_gen/src/test_data_gen_local/__init__.py b/examples/test_data_gen/src/test_data_gen_local/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/src/test_data_gen_local/config.ini similarity index 100% rename from examples/test_data_gen/test_data_gen_local/config.ini rename to examples/test_data_gen/src/test_data_gen_local/config.ini diff --git a/examples/test_data_gen/test_data_gen_local/requirements.txt b/examples/test_data_gen/src/test_data_gen_local/requirements.txt similarity index 100% rename from examples/test_data_gen/test_data_gen_local/requirements.txt rename to examples/test_data_gen/src/test_data_gen_local/requirements.txt diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py similarity index 65% rename from examples/test_data_gen/test_data_gen_local/run_test_data_gen.py rename to examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py index 5517115bdbd..4fc401aef01 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py @@ -1,43 +1,39 @@ -import json import os from datetime import datetime import configargparse -from constants import TEXT_CHUNK -from doc_split import split_doc from promptflow import PFClient from promptflow.entities import Run +UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "src", "utils")) +if UTILS_PATH not in os.sys.path: + os.sys.path.insert(0, UTILS_PATH) + +from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE +from common import split_document, clean_data_and_save + CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) def batch_run_flow( - pf: PFClient, - flow_folder: str, - flow_input_data: str, - flow_batch_run_size: int, - connection_name: str = "azure_open_ai_connection", + pf: PFClient, + flow_folder: str, + flow_input_data: str, + flow_batch_run_size: int, + connection_name: str = "azure_open_ai_connection", ): - environment_variables = { - "PF_WORKER_COUNT": str(flow_batch_run_size), - "PF_BATCH_METHOD": "spawn", - } # TODO: what does 'spawn' mean? - print("start to run batch flow run.") - # create run base_run = pf.run( flow=flow_folder, data=flow_input_data, - stream=True, # TODO: understand 'stream' - environment_variables=environment_variables, - connections={ - "validate_and_generate_seed_question": {"connection": connection_name}, - "validate_and_generate_test_question": {"connection": connection_name}, - "validate_test_question": {"connection": connection_name}, - "generate_ground_truth": {"connection": connection_name}, - "validate_ground_truth": {"connection": connection_name}, + stream=True, + environment_variables={ + "PF_WORKER_COUNT": str(flow_batch_run_size), + "PF_BATCH_METHOD": "spawn", }, + connections={key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items()}, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, ) @@ -58,20 +54,6 @@ def get_batch_run_output(pf: PFClient, base_run: Run): return [{"question": q, "ground_truth": g, "debug_info": d} for q, g, d in zip(question, ground_truth, debug_info)] -def clean_data_and_save(test_data_set: list, test_data_output_path: str): - cleaned_data = [ - test_data - for test_data in test_data_set - if (test_data and all(val for key, val in test_data.items() if key.lower() != "line_number")) - ] - - jsonl_str = "\n".join(map(json.dumps, cleaned_data)) - - cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") - with open(os.path.join(test_data_output_path, "test-data-" + cur_time_str + ".jsonl"), "wt") as text_file: - print(f"{jsonl_str}", file=text_file) - - if __name__ == "__main__": if os.path.isfile(CONFIG_FILE): parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) @@ -101,17 +83,26 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): # check_file_path_exists(args.test_data_output_path) if not args.should_skip_doc_split: - split_doc(args.documents_folder, args.document_nodes_output_path, args.document_chunk_size) + if not os.path.exists(args.document_nodes_output_path): + os.makedirs(args.document_nodes_output_path) + + output = split_document(args.document_chunk_size, args.documents_folder, args.document_nodes_output_path) pf = PFClient() # TODO: error handling batch_run = batch_run_flow( pf, args.flow_folder, - args.document_nodes_output_path, + output, args.flow_batch_run_size, connection_name=args.connection_name, ) test_data_set = get_batch_run_output(pf, batch_run) - clean_data_and_save(test_data_set, args.test_data_output_path) + + cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") + if not os.path.exists(args.test_data_output_path): + os.makedirs(args.test_data_output_path) + + output = os.path.join(args.test_data_output_path, "test-data-" + cur_time_str + ".jsonl") + clean_data_and_save(test_data_set, output) diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/__init__.py b/examples/test_data_gen/src/test_data_gen_pipeline/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/test_data_gen_pipeline/config.ini b/examples/test_data_gen/src/test_data_gen_pipeline/config.ini similarity index 94% rename from examples/test_data_gen/test_data_gen_pipeline/config.ini rename to examples/test_data_gen/src/test_data_gen_pipeline/config.ini index 57105a693b3..26537b1f243 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/config.ini +++ b/examples/test_data_gen/src/test_data_gen_pipeline/config.ini @@ -14,4 +14,4 @@ flow_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_ ; Parallel run step configs prs_instance_count = 2 prs_mini_batch_size = "10kb" -prs_max_concurrency_per_instance = 10 +prs_max_concurrency_per_instance = 10 \ No newline at end of file diff --git a/examples/test_data_gen/test_data_gen_pipeline/requirements.txt b/examples/test_data_gen/src/test_data_gen_pipeline/requirements.txt similarity index 100% rename from examples/test_data_gen/test_data_gen_pipeline/requirements.txt rename to examples/test_data_gen/src/test_data_gen_pipeline/requirements.txt diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py new file mode 100644 index 00000000000..abf588912e5 --- /dev/null +++ b/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -0,0 +1,112 @@ +import os + +import configargparse +from azure.ai.ml import Input, MLClient, dsl, load_component +from azure.identity import DefaultAzureCredential + +UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "src", "utils")) +if UTILS_PATH not in os.sys.path: + os.sys.path.insert(0, UTILS_PATH) + +from components import clean_test_data_set, document_split +from constants import CONNECTIONS_TEMPLATE + + +def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): + credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) + return MLClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group, + workspace_name=workspace_name, + ) + + +@dsl.pipeline( + non_pipeline_inputs=[ + "flow_yml_path", + "should_skip_doc_split", + "instance_count", + "mini_batch_size", + "max_concurrency_per_instance", + ] +) +def test_data_gen_pipeline_with_flow( + data_input: Input, + flow_yml_path: str, + connection_name: str, # ?? should we override here? + should_skip_doc_split: bool, + chunk_size=1024, + instance_count=1, + mini_batch_size="10kb", + max_concurrency_per_instance=2, +): + data = data_input if should_skip_doc_split else document_split(documents_folder=data_input, + chunk_size=chunk_size).outputs.document_node_output + flow_node = load_component(flow_yml_path)( + data=data, + text_chunk="${data.text_chunk}", + connections={key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items()}, + ) + + flow_node.mini_batch_size = mini_batch_size + flow_node.max_concurrency_per_instance = max_concurrency_per_instance + flow_node.set_resources(instance_count=instance_count) + + clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) + + +if __name__ == "__main__": + CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) + + if not os.path.isfile(CONFIG_FILE): + raise Exception(f"'{CONFIG_FILE}' does not exist. Please check your directory or if the file is missing.") + + parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + parser.add_argument("--subscription_id", required=True, help="AzureML workspace subscription id") + parser.add_argument("--resource_group", required=True, help="AzureML workspace resource group name") + parser.add_argument("--workspace_name", required=True, help="AzureML workspace name") + parser.add_argument("--aml_cluster", required=True, help="AzureML cluster name") + parser.add_argument("--should_skip_doc_split", action="store_true", help="Skip doc split or not") + parser.add_argument("--document_nodes_file_path", help="Splitted document nodes file path") + parser.add_argument("--documents_folder", help="Documents folder path") + parser.add_argument("--document_chunk_size", type=int, help="Document chunk size") + parser.add_argument("--flow_path", required=True, help="Test data generation flow path") + parser.add_argument("--connection_name", required=True, help="Promptflow connection name") + parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") + parser.add_argument("--prs_mini_batch_size", help="Parallel run step mini batch size") + parser.add_argument("--prs_max_concurrency_per_instance", type=int, + help="Parallel run step max concurrency per instance") + + args = parser.parse_args() + + if args.should_skip_doc_split and not args.document_nodes_file_path: + parser.error("--document_nodes_file_path is required when --should_skip_doc_split is True") + elif not args.should_skip_doc_split and not args.documents_folder: + parser.error("--documents_folder is required when --should_skip_doc_split is False") + + ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) + + if args.should_skip_doc_split: + data_input = Input(path=args.document_nodes_file_path, type="uri_file") + else: + data_input = Input(path=args.documents_folder, type="uri_folder") + + prs_configs = { + "instance_count": args.prs_instance_count, + "mini_batch_size": args.prs_mini_batch_size, + "max_concurrency_per_instance": args.prs_max_concurrency_per_instance, + } + + pipeline_with_flow = test_data_gen_pipeline_with_flow( + data_input=data_input, + flow_yml_path=args.flow_path, + connection_name=args.connection_name, + should_skip_doc_split=args.should_skip_doc_split, + chunk_size=args.document_chunk_size, + **prs_configs, + ) + pipeline_with_flow.compute = args.aml_cluster + + ml_client.jobs.create_or_update(pipeline_with_flow) diff --git a/examples/test_data_gen/src/utils/__init__.py b/examples/test_data_gen/src/utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/src/utils/common.py b/examples/test_data_gen/src/utils/common.py new file mode 100644 index 00000000000..9a13f01e7c9 --- /dev/null +++ b/examples/test_data_gen/src/utils/common.py @@ -0,0 +1,51 @@ +import json +import os +import typing as t +from pathlib import Path + +from constants import DOCUMENT_NODE, TEXT_CHUNK + +try: + from llama_index import SimpleDirectoryReader + from llama_index.node_parser import SentenceSplitter + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + + +def split_document(chunk_size, documents_folder, document_node_output): + # load docs + documents = SimpleDirectoryReader( + documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" + ).load_data() + # Convert documents into nodes + node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) + documents = t.cast(t.List[LlamaindexDocument], documents) + document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) + + with open(os.path.join(document_node_output, "document_nodes.jsonl"), "wt") as text_file: + for doc in document_nodes: + print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) + + return str((Path(document_node_output) / "document_nodes.jsonl")) + + +def clean_data_and_save(test_data_set: list, test_data_output_path: str): + cleaned_data = [ + test_data + for test_data in test_data_set + if (test_data and all(val for key, val in test_data.items() if key.lower() != "line_number")) + ] + + jsonl_str = "\n".join(map(json.dumps, cleaned_data)) + with open(test_data_output_path, "wt") as text_file: + print(f"{jsonl_str}", file=text_file) + + +NNNN = { + +} + diff --git a/examples/test_data_gen/src/utils/components.py b/examples/test_data_gen/src/utils/components.py new file mode 100644 index 00000000000..afb0286d649 --- /dev/null +++ b/examples/test_data_gen/src/utils/components.py @@ -0,0 +1,64 @@ +import json +import os +from pathlib import Path + +from mldesigner import Input, Output, command_component +from common import split_document, clean_data_and_save +from constants import ENVIRONMENT_DICT_FIXED_VERSION + +try: + from llama_index import SimpleDirectoryReader + from llama_index.node_parser import SentenceSplitter + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + + +@command_component( + name="document_split", + version="1.0.4", + display_name="Split documents", + description="Split documents into chunks.", + environment=ENVIRONMENT_DICT_FIXED_VERSION, +) +def document_split( + documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") +) -> str: + """Split documents into chunks. + + Args: + documents_folder: The folder containing documents to be split. + chunk_size: The size of each chunk. + document_node_output: The output folder + + Returns: + The folder containing the split documents. + """ + print("files in input path: ", os.listdir(documents_folder)) + return split_document(chunk_size, documents_folder, document_node_output) + + +@command_component( + name="clean_test_data_set", + version="1.0.4", + display_name="Clean dataset", + description="Clean test data set to remove empty lines.", + environment=ENVIRONMENT_DICT_FIXED_VERSION, +) +def clean_test_data_set( + test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") +) -> str: + test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" + print("test_data_file path: %s" % test_data_set_path) + + print("reading file: %s ..." % test_data_set_path) + with open(test_data_set_path, "r") as f: + data = [json.loads(line) for line in f] + + test_data_output_path = os.path.join(test_data_output, "test_data_set.jsonl") + clean_data_and_save(data, test_data_output_path) + + return test_data_output_path diff --git a/examples/test_data_gen/src/utils/constants.py b/examples/test_data_gen/src/utils/constants.py new file mode 100644 index 00000000000..339f64ba6ad --- /dev/null +++ b/examples/test_data_gen/src/utils/constants.py @@ -0,0 +1,30 @@ +DOCUMENT_NODE = "document_node" +TEXT_CHUNK = "text_chunk" + +ENVIRONMENT_DICT_FIXED_VERSION = dict( + image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", + conda_file={ + "name": "test_data_gen_conda_env", + "channels": ["defaults"], + "dependencies": [ + "python=3.10.12", + "pip=23.2.1", + { + "pip": [ + "--extra-index-url=https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/", + "mldesigner==0.1.0b17", + "llama_index", + "docx2txt" + ] + }, + ], + } +) + +CONNECTIONS_TEMPLATE = { + "validate_and_generate_seed_question": {"connection": "{connection_name}"}, + "validate_and_generate_test_question": {"connection": "{connection_name}"}, + "validate_test_question": {"connection": "{connection_name}"}, + "generate_ground_truth": {"connection": "{connection_name}"}, + "validate_ground_truth": {"connection": "{connection_name}"} +} diff --git a/examples/test_data_gen/test_data_gen_local/constants.py b/examples/test_data_gen/test_data_gen_local/constants.py deleted file mode 100644 index e3e6d1de170..00000000000 --- a/examples/test_data_gen/test_data_gen_local/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -DOCUMENT_NODE = "document_node" -TEXT_CHUNK = "text_chunk" diff --git a/examples/test_data_gen/test_data_gen_local/doc_split.py b/examples/test_data_gen/test_data_gen_local/doc_split.py deleted file mode 100644 index bb2840f97f9..00000000000 --- a/examples/test_data_gen/test_data_gen_local/doc_split.py +++ /dev/null @@ -1,50 +0,0 @@ -import argparse -import json -import typing as t - -from llama_index import SimpleDirectoryReader -from llama_index.readers import BeautifulSoupWebReader - -try: - from llama_index.node_parser import SentenceSplitter - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - -from constants import DOCUMENT_NODE, TEXT_CHUNK - - -def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, urls: list = None): - # load docs - if urls: - documents = BeautifulSoupWebReader().load_data(urls=urls) - else: - documents = SimpleDirectoryReader( - documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" - ).load_data() - - # Convert documents into nodes - node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) - documents = t.cast(t.List[LlamaindexDocument], documents) - document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - - jsonl_str = "" - for doc in document_nodes: - json_dict = {TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()} - jsonl_str += json.dumps(json_dict) + "\n" - - with open(output_file_path, "wt") as text_file: - print(f"{jsonl_str}", file=text_file) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--documents_folder", type=str, required=True) - parser.add_argument("--chunk_size", type=int, required=False, default=1024) - parser.add_argument("--document_node_output", type=str, required=True) - args = parser.parse_args() - - split_doc(args.documents_folder, args.document_node_output, args.chunk_size) diff --git a/examples/test_data_gen/test_data_gen_pipeline/components.py b/examples/test_data_gen/test_data_gen_pipeline/components.py deleted file mode 100644 index 988546d31e4..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/components.py +++ /dev/null @@ -1,101 +0,0 @@ -import json -import os -import typing as t -from pathlib import Path - -from constants import DOCUMENT_NODE, TEXT_CHUNK -from mldesigner import Input, Output, command_component - -try: - from llama_index import SimpleDirectoryReader - from llama_index.node_parser import SentenceSplitter - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - - -@command_component( - name="document_split", - version="1", - display_name="Split documents", - description="Split documents into chunks.", - environment=dict( - conda_file=Path(__file__).parent / "conda.yml", - image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", - ), -) -def document_split( - documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") -) -> str: - """Split documents into chunks. - - Args: - documents_folder: The folder containing documents to be split. - chunk_size: The size of each chunk. - - Returns: - The folder containing the split documents. - """ - print("files in input path: ") - arr = os.listdir(documents_folder) - print(arr) - - # load docs - documents = SimpleDirectoryReader( - documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" - ).load_data() - # Convert documents into nodes - node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) - documents = t.cast(t.List[LlamaindexDocument], documents) - document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - - jsonl_str = "" - for doc in document_nodes: - json_dict = {TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()} - jsonl_str += json.dumps(json_dict) + "\n" - - with open(os.path.join(document_node_output, "document_nodes.jsonl"), "wt") as text_file: - print(f"{jsonl_str}", file=text_file) - - return str((Path(document_node_output) / "document_nodes.jsonl")) - - -@command_component( - name="clean_test_data_set", - version="1", - display_name="Clean dataset", - description="Clean test data set to remove empty lines.", - environment=dict( - conda_file=Path(__file__).parent / "conda.yml", - image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", - ), -) -def clean_test_data_set( - test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") -) -> str: - test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" - print("test_data_file path: %s" % test_data_set_path) - - print("reading file: %s ..." % test_data_set_path) - with open(test_data_set_path, "r") as f: - data = [json.loads(line) for line in f] - - # Filter out empty dictionaries - # TODO: error handling - filtered_data = [ - {"question": d["question"], "ground_truth": d["ground_truth"], "debug_info": d["debug_info"]} - for d in data - if (d and all(val for key, val in d.items() if key.lower() != "line_number")) - ] - - jsonl_str = "" - for d in filtered_data: - jsonl_str += json.dumps(d) + "\n" - - with open(os.path.join(test_data_output, "test_data_set.jsonl"), "wt") as text_file: - print(f"{jsonl_str}", file=text_file) - - return str((Path(test_data_output) / "test_data_set.jsonl")) diff --git a/examples/test_data_gen/test_data_gen_pipeline/conda.yml b/examples/test_data_gen/test_data_gen_pipeline/conda.yml deleted file mode 100644 index 6ffb3338c0d..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/conda.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: test_data_gen_conda_env -channels: - - defaults -dependencies: - - python=3.10.12 - - pip=23.2.1 - - pip: - - mldesigner==0.1.0b17 - - llama_index diff --git a/examples/test_data_gen/test_data_gen_pipeline/constants.py b/examples/test_data_gen/test_data_gen_pipeline/constants.py deleted file mode 100644 index e3e6d1de170..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -DOCUMENT_NODE = "document_node" -TEXT_CHUNK = "text_chunk" diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py deleted file mode 100644 index 3093200921e..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ /dev/null @@ -1,126 +0,0 @@ -import os - -import configargparse -from azure.ai.ml import Input, MLClient, dsl, load_component -from azure.identity import DefaultAzureCredential -from components import clean_test_data_set, document_split - -CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) - - -def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): - credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) - ml_client = MLClient( - credential=credential, - subscription_id=subscription_id, - resource_group_name=resource_group, - workspace_name=workspace_name, - ) - - return ml_client - - -@dsl.pipeline( - non_pipeline_inputs=[ - "flow_yml_path", - "should_skip_doc_split", - "instance_count", - "mini_batch_size", - "max_concurrency_per_instance", - ] -) -def test_data_gen_pipeline_with_flow( - data_input, - flow_yml_path: str, - connection_name: str, # ?? should we override here? - should_skip_doc_split: bool, - chunk_size=1024, - instance_count=1, - mini_batch_size="10kb", - max_concurrency_per_instance=2, -): - if should_skip_doc_split: - data = data_input - else: - document_node = document_split(documents_folder=data_input, chunk_size=chunk_size) - data = document_node.outputs.document_node_output - - flow_component = load_component(flow_yml_path) - flow_node = flow_component( - data=data, - text_chunk="${data.text_chunk}", - connections={ - "validate_and_generate_seed_question": {"connection": connection_name}, - "validate_and_generate_test_question": {"connection": connection_name}, - "validate_test_question": {"connection": connection_name}, - "generate_ground_truth": {"connection": connection_name}, - "validate_ground_truth": {"connection": connection_name}, - }, - ) - - flow_node.mini_batch_size = mini_batch_size - flow_node.max_concurrency_per_instance = max_concurrency_per_instance - flow_node.set_resources(instance_count=instance_count) - - clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) - - -if __name__ == "__main__": - if os.path.isfile(CONFIG_FILE): - parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) - else: - raise Exception( - f"'{CONFIG_FILE}' does not exist. " - + "Please check if you are under the wrong directory or the file is missing." - ) - parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) - parser.add_argument("--subscription_id", required=True, type=str, help="AzureML workspace subscription id") - parser.add_argument("--resource_group", required=True, type=str, help="AzureML workspace resource group name") - parser.add_argument("--workspace_name", required=True, type=str, help="AzureML workspace name") - parser.add_argument("--aml_cluster", required=True, type=str, help="AzureML cluster name") - parser.add_argument("--should_skip_doc_split", action="store_true", help="Skip doc split or not") - parser.add_argument( - "--document_nodes_file_path", required=False, type=str, help="Splitted document nodes file path" - ) - parser.add_argument("--documents_folder", required=False, type=str, help="Documents folder path") - parser.add_argument("--document_chunk_size", required=False, type=int, help="Document chunk size") - parser.add_argument("--flow_path", required=True, type=str, help="Test data generation flow path") - parser.add_argument("--connection_name", required=True, type=str, help="Promptflow connection name") - parser.add_argument("--prs_instance_count", required=False, type=int, help="Parallel run step instance count") - parser.add_argument("--prs_mini_batch_size", required=False, type=str, help="Parallel run step mini batch size") - parser.add_argument( - "--prs_max_concurrency_per_instance", - required=False, - type=int, - help="Parallel run step max concurrency per instance", - ) - args = parser.parse_args() - if args.should_skip_doc_split and args.document_nodes_file_path is None: - parser.error("--document_nodes_file_path is required when --should_skip_doc_split is True") - elif not args.should_skip_doc_split and args.documents_folder is None: - parser.error("--documents_folder is required when --should_skip_doc_split is False") - - ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) - - if args.should_skip_doc_split: - data_input = Input(path=args.document_nodes_file_path, type="uri_file") - else: - data_input = Input(path=args.documents_folder, type="uri_folder") - - prs_configs = { - "instance_count": args.prs_instance_count, - "mini_batch_size": args.prs_mini_batch_size, - "max_concurrency_per_instance": args.prs_max_concurrency_per_instance, - } - - pipeline_with_flow = test_data_gen_pipeline_with_flow( - data_input=data_input, - flow_yml_path=args.flow_path, - connection_name=args.connection_name, - should_skip_doc_split=args.should_skip_doc_split, - chunk_size=args.document_chunk_size, - **prs_configs, - ) - pipeline_with_flow.compute = args.aml_cluster - - ml_client.jobs.create_or_update(pipeline_with_flow) From 9f7ff03c1fadb543c4d86693e575f576f4b7fdef Mon Sep 17 00:00:00 2001 From: yalu4 Date: Fri, 26 Jan 2024 15:44:06 +0800 Subject: [PATCH 022/112] update data construction doc --- docs/how-to-guides/construct-test-data.md | 110 ++++++++++++++++------ 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index c8412cfc5eb..fc8a3bb6944 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -1,44 +1,96 @@ # How to construct test data based on documents -This guide will help to construct test data based on the provided documents. -The test data construction process contains three steps: -- Split documents to smaller trunks. -- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`. -By `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional. -- Collect all the test data and remove empty values. - -## Data preprocess -### Local -#### Prerequisites +This guide will instruct you on how to generate test data for RAG systems utilizing existing documents. +Previously evaluating the performance of RAG systems required the creation of test data. This could be done manually, a process that required significant time and effort, or by purchasing pre-made test data, which could be costly. + +This test data generation process streamlines this by leveraging the capabilities of llm to automatically generate the test data. This not only reduces the effort required but also eliminates the need for additional expenditures. + +By following this guide, you will learn how to: +1. Customize the test data generation process by tuning flow prompts. +2. Generate high-quality test data quickly and easily by running a test data generation script. + +**Supported file types** +- .md - Markdown +- .docx - Microsoft Word +- .pdf - Portable Document Format +- .ipynb - Jupyter Notebook + +**Limitations** + +- While the test data generator works well with standard documents, it may face challenges with API introduction documents or reference documents. +- Additionally, it may not function effectively for non-Latin characters, such as Chinese. These limitations may be due to the text loader capabilities such as pypdf. + +## Quick start +- Install required packages Enter `test_data_gen_local` folder, run below command to install required packages. -```bash -pip install -r requirements.txt -``` + ```bash + pip install -r requirements.txt + ``` -#### Get started -- Enter [construct_test_data_flow folder](../../examples/test_data_gen/construct_test_data_flow/) to tune your prompt in order to customize your own test data gen logic. -> [!Note] This step can be skipped if you just want to have a try. + For specific document file types, you will need to install extra packages: + > !Note: This package requirement may be outdated. In this process, we utilize llama index `SimpleDirectoryReador`. For the most recent information, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + - .docx - `pip install docx2txt` + - .pdf - `pip install pypdf` + - .ipynb - `pip install nbconvert` -- Enter [test_data_gen_local folder](../../examples/test_data_gen/test_data_gen_local) - - Update configs in `configs.ini` - - After configuration, run below command to gen test data set. +- Run and tune test data construction flow + - Navigate to the [construct_test_data_flow folder](../../examples/test_data_gen/construct_test_data_flow/). Open the `flow.dag.yaml` to understand the structure of the data flow. Fill in necessary values like connections and model/deployment name. + - Ensure the `flow.tools.json` is generated under `.promptflow` folder within the flow folder. + - Check the guide [init-and-test-a-flow](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html) to test the flow. + - [*Optional*] Customize your test data generation logic. Refer to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html) for more guidance. Once you updated the flow, ensure the flow can complete successfully before preceding to next steps to generate bulk data. + + **Understand the prompts** + + The test data construction flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, ground truths, etc., while validation prompts are used to verify the validity of the text trunk, generated question or ground truth. + - Generation prompts + - *generate question prompt*: frame a question based on the given text trunk. + - *generate ground truth prompt*: generate ground truth for the question based on the given text trunk. + - Validation prompts + - *validate text trunk prompt*: validate if the given text trunk is worthy of framing a question. + - *validate seed/test question prompt*: validate if the generated question can be clearly understood. + - *validate ground truth*: validate if the generated ground truth is clear and certain. + + If the validation fails, the corresponding output would be an empty string so that the invalid data would not be incorporated into the final test data set. + + **Set the appropriate model and corresponding response format**: + + The `gpt-4` model is recommended. The default prompt may yield better results with this model compared to the gpt-3 series. + - For the `gpt-4` model with version `0613`, use the response format `text`. + - For the `gpt-4` model with version `1106`, use the response format `json`. + +- Run data generation script + - Enter [test_data_gen_local folder](../../examples/test_data_gen/test_data_gen_local). + - Update the configurations in the `configs.ini` file. Here is a brief of introduction of each parameter: + > // TODO: or move this part as comment in config ini? + - *should_skip_doc_split*: Document split step can be reused. If you have already splitted the documents, and in next time you just want to generate the test data based on these document chunks, you can set the value as `True` to skip the document split step. + - *documents_folder*: the source path of text to be splitted into text trunks for question and ground truth generation. + - *document_chunk_size*: chunk size is used to determine the size of each text chunk + > !Note: In this guidance, we leverage llama_index to do text chunking. There are two steps of document splitting: + > + > a. Each document would be splitted roughly based on different document file types. Markdown file would be splitted by Heading, pdf file would be splitted by pages. + > b. For each splitted document chunk, it would get further splitted by chunk size. Chunk size may not seem to work if the text token size is smaller than chunk size. + - *document_nodes_output_path*: //TODO: make it a default folder without need to configure. + - *flow_folder*: //TODO: can we use relative path so that there is no need to configure the flow folder path either. + - *connection_name*: //TODO: do we need to provide the option to override the connection in script. + - *test_data_output_path*: output path of generated test data set. + - After configuration, run the following command to generate the test data set: ```bash python run_test_data_gen.py ``` - - The generated test data would be a data jsonl file with path you configured in `config.ini` + - The generated test data will be a data jsonl file located in the path you configured in `config.ini`. + -### Cloud -If you want to deal with large test data, you can leverage PRS to run flow in pipeline. -#### Prerequisites -Enter `test_data_gen_pipeline` folder, run below command to install required packages. -```bash -pip install -r requirements.txt -``` +## Cloud +For handling larger test data, you can leverage the PRS component to run flow in pipeline. +- Prerequisites + Enter `test_data_gen_pipeline` folder, run below command to install required packages. + ```bash + pip install -r requirements.txt + ``` -#### Get started - Enter [test_data_gen_pipeline folder](../../examples/test_data_gen/test_data_gen_pipeline) - Update configs in `configs.ini` - After configuration, run below command to gen test data set. ```bash python run_test_data_gen_pipeline.py ``` - - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use. \ No newline at end of file + - The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. From 418bdfe76f3aecb227041fa1692c5c526d94ea23 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:25:02 +0800 Subject: [PATCH 023/112] Add mode logs (#1865) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- .../src/test_data_gen_local/run_test_data_gen.py | 12 +++++++----- .../run_test_data_gen_pipeline.py | 10 +++++----- examples/test_data_gen/src/utils/common.py | 10 +++++----- examples/test_data_gen/src/utils/components.py | 10 ---------- examples/test_data_gen/src/utils/constants.py | 1 - 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py index 4fc401aef01..d9f72af02fc 100644 --- a/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py @@ -10,8 +10,8 @@ if UTILS_PATH not in os.sys.path: os.sys.path.insert(0, UTILS_PATH) -from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE -from common import split_document, clean_data_and_save +from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE # noqa: E402 +from common import split_document, clean_data_and_save # noqa: E402 CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) @@ -23,7 +23,7 @@ def batch_run_flow( flow_batch_run_size: int, connection_name: str = "azure_open_ai_connection", ): - print("start to run batch flow run.") + print("#### Start to submit the batch run.") base_run = pf.run( flow=flow_folder, data=flow_input_data, @@ -38,11 +38,13 @@ def batch_run_flow( debug=True, ) + print("#### Batch run is completed.") + return base_run def get_batch_run_output(pf: PFClient, base_run: Run): - print(f"Start to get batch run {base_run} details.") + print(f"#### Start to get batch run {base_run.name} details.") # get run output details = pf.get_details(base_run, all_results=True) @@ -81,7 +83,7 @@ def get_batch_run_output(pf: PFClient, base_run: Run): if not (args.documents_folder or args.document_nodes_output_path): parser.error("Either 'documents_folder' or 'document_nodes_output_path' should be specified.") - # check_file_path_exists(args.test_data_output_path) + output = args.document_nodes_output_path if not args.should_skip_doc_split: if not os.path.exists(args.document_nodes_output_path): os.makedirs(args.document_nodes_output_path) diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py index abf588912e5..3b312c57f84 100644 --- a/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -8,8 +8,8 @@ if UTILS_PATH not in os.sys.path: os.sys.path.insert(0, UTILS_PATH) -from components import clean_test_data_set, document_split -from constants import CONNECTIONS_TEMPLATE +from components import clean_test_data_set, document_split # noqa: E402 +from constants import CONNECTIONS_TEMPLATE # noqa: E402 def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): @@ -47,7 +47,7 @@ def test_data_gen_pipeline_with_flow( data=data, text_chunk="${data.text_chunk}", connections={key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items()}, + for key, value in CONNECTIONS_TEMPLATE.items()}, ) flow_node.mini_batch_size = mini_batch_size @@ -108,5 +108,5 @@ def test_data_gen_pipeline_with_flow( **prs_configs, ) pipeline_with_flow.compute = args.aml_cluster - - ml_client.jobs.create_or_update(pipeline_with_flow) + print("Completed to submit pipeline. Experiment Link: ", + ml_client.jobs.create_or_update(pipeline_with_flow).studio_url) diff --git a/examples/test_data_gen/src/utils/common.py b/examples/test_data_gen/src/utils/common.py index 9a13f01e7c9..fad1425a685 100644 --- a/examples/test_data_gen/src/utils/common.py +++ b/examples/test_data_gen/src/utils/common.py @@ -18,6 +18,7 @@ def split_document(chunk_size, documents_folder, document_node_output): # load docs + print("#### Start to split the documents.") documents = SimpleDirectoryReader( documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" ).load_data() @@ -30,10 +31,13 @@ def split_document(chunk_size, documents_folder, document_node_output): for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) + print(f"#### End to split the documents and generate {len(document_nodes)} text chunks.") + return str((Path(document_node_output) / "document_nodes.jsonl")) def clean_data_and_save(test_data_set: list, test_data_output_path: str): + print("#### Start to clean the data.") cleaned_data = [ test_data for test_data in test_data_set @@ -44,8 +48,4 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): with open(test_data_output_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - -NNNN = { - -} - + print(f"#### Completed to generate the {len(cleaned_data)} test data and store to {test_data_output_path}.") diff --git a/examples/test_data_gen/src/utils/components.py b/examples/test_data_gen/src/utils/components.py index afb0286d649..914573bccb5 100644 --- a/examples/test_data_gen/src/utils/components.py +++ b/examples/test_data_gen/src/utils/components.py @@ -6,16 +6,6 @@ from common import split_document, clean_data_and_save from constants import ENVIRONMENT_DICT_FIXED_VERSION -try: - from llama_index import SimpleDirectoryReader - from llama_index.node_parser import SentenceSplitter - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - @command_component( name="document_split", diff --git a/examples/test_data_gen/src/utils/constants.py b/examples/test_data_gen/src/utils/constants.py index 339f64ba6ad..48a47eb70fe 100644 --- a/examples/test_data_gen/src/utils/constants.py +++ b/examples/test_data_gen/src/utils/constants.py @@ -11,7 +11,6 @@ "pip=23.2.1", { "pip": [ - "--extra-index-url=https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/", "mldesigner==0.1.0b17", "llama_index", "docx2txt" From 945c0f920c62244a650befe4d9f82efc32119aa4 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Mon, 29 Jan 2024 18:09:10 +0800 Subject: [PATCH 024/112] add debug info --- .../construct_test_data_flow/flow.dag.yaml | 14 +++- .../generate_debug_info.py | 69 ++++++++++++++++- .../src/construct_test_data_flow/utils.py | 74 ++++++++++--------- .../validate_and_generate_seed_question.py | 18 +++-- .../validate_and_generate_test_question.py | 41 ++++++---- .../validate_ground_truth.py | 21 +++--- .../validate_test_question.py | 6 +- .../validate_text_trunk_prompt.jinja2 | 4 +- examples/test_data_gen/src/utils/common.py | 12 +-- 9 files changed, 181 insertions(+), 78 deletions(-) diff --git a/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml index 1cdc9a65037..2f1fcdc7130 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml @@ -5,13 +5,16 @@ inputs: text_chunk: type: string is_chat_input: false + text_meta: + type: string + default: "{}" outputs: question: type: string reference: ${validate_test_question.output} ground_truth: type: string - reference: ${validate_ground_truth.output} + reference: ${validate_ground_truth.output.ground_truth} debug_info: type: string reference: ${generate_debug_info.output} @@ -30,7 +33,7 @@ nodes: type: code path: validate_question_prompt.jinja2 inputs: - question: ${validate_and_generate_seed_question.output} + question: ${validate_and_generate_seed_question.output.question} use_variants: false - name: seed_question_prompt type: prompt @@ -70,7 +73,8 @@ nodes: connection: model: gpt-4 validate_seed_question_prompt: ${validate_seed_question_prompt.output} - seed_question: ${validate_and_generate_seed_question.output} + seed_question: ${validate_and_generate_seed_question.output.question} + response_format: "" use_variants: false - name: validate_question_prompt type: prompt @@ -111,6 +115,10 @@ nodes: inputs: question_type: ${validate_and_generate_test_question.output.question_type} text_trunk: ${inputs.text_chunk} + text_meta: ${inputs.text_meta} + validate_and_generate_seed_question_output: ${validate_and_generate_seed_question.output} + validate_and_generate_test_question_output: ${validate_and_generate_test_question.output} + validate_ground_truth_output: ${validate_ground_truth.output} - name: validate_ground_truth_prompt type: prompt source: diff --git a/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py b/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py index fa1d80f4937..aea76b6ac4e 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py +++ b/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py @@ -1,3 +1,5 @@ +from utils import ValidateObj, ValidationResult + from promptflow import tool @@ -5,5 +7,68 @@ # Adding type to arguments and return value will help the system show the types properly # Please update the function name/signature per need @tool -def my_python_tool(question_type: str, text_trunk: str) -> dict: - return {"question_type": question_type, "text_trunk": text_trunk} +def my_python_tool( + question_type: str, + text_trunk: str, + text_meta: dict = None, + validate_and_generate_seed_question_output: dict = None, + validate_and_generate_test_question_output: dict = None, + validate_ground_truth_output: ValidationResult = None, +) -> dict: + text_trunk_validation_res = validate_and_generate_seed_question_output["validation_res"] + generated_seed_question = validate_and_generate_seed_question_output["question"] + seed_question_validation_res = validate_and_generate_test_question_output["validation_res"] + generated_ground_truth = validate_ground_truth_output["ground_truth"] + ground_truth_validation_res = validate_ground_truth_output["validation_res"] + + is_generation_success = generated_ground_truth != "" + is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None + is_seed_question_valid = seed_question_validation_res.pass_validation if seed_question_validation_res else None + is_ground_truth_valid = ground_truth_validation_res.pass_validation if ground_truth_validation_res else None + + failed_step = "" + failed_reason = "" + if not is_generation_success: + if is_text_trunk_valid is False: + failed_step = ValidateObj.TEXT_TRUNK + failed_reason = text_trunk_validation_res.reason_if_failed + elif is_seed_question_valid is False: + failed_step = ValidateObj.QUESTION + failed_reason = seed_question_validation_res.reason_if_failed + elif is_ground_truth_valid is False: + failed_step = ValidateObj.GROUND_TRUTH + failed_reason = ground_truth_validation_res.reason_if_failed + + return { + "question_type": question_type, + "text_trunk": text_trunk, + "text_meta": text_meta, + "generation_summary": { + "success": is_generation_success, + "failed_step": failed_step, + "failed_reason": failed_reason, + }, + "generation_details": { + "text_trunk": { + "pass_validation": is_text_trunk_valid, + "reason_if_failed": text_trunk_validation_res.reason_if_failed + if is_text_trunk_valid is False + else None, + }, + "seed_question": { + "generated_question": generated_seed_question, + "pass_validation": is_seed_question_valid, + "reason_if_failed": seed_question_validation_res.reason_if_failed + if is_seed_question_valid is False + else None, + }, + # "test_question": {}, # placeholder for evolved questions like multi-context, reasoning, etc. + "ground_truth": { + "generated_ground_truth": generated_ground_truth, + "pass_validation": is_ground_truth_valid, + "reason_if_failed": ground_truth_validation_res.reason_if_failed + if is_ground_truth_valid is False + else None, + }, + }, + } diff --git a/examples/test_data_gen/src/construct_test_data_flow/utils.py b/examples/test_data_gen/src/construct_test_data_flow/utils.py index a2d5d934407..f1d1bddc7ea 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/src/construct_test_data_flow/utils.py @@ -1,12 +1,15 @@ import json +import re +from collections import namedtuple +from enum import Enum import numpy as np import numpy.testing as npt from numpy.random import default_rng -from promptflow.tools.aoai import chat as aoai_chat -from promptflow.tools.openai import chat as openai_chat from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.tools.aoai import chat as aoai_chat +from promptflow.tools.openai import chat as openai_chat class QuestionType: @@ -19,24 +22,31 @@ class QuestionType: class ValidateObj: QUESTION = "question" TEXT_TRUNK = "text_trunk" - GROUNDTRUTH = "ground_truth" + GROUND_TRUTH = "ground_truth" + + +class ResponseFormat(Enum): + TEXT = "text" + JSON = "json_object" + + +class ErrorMsg: + INVALID_JSON_FORMAT = "llm failed to return the verdict and reason in correct json format. Response: {0}" + INVALID_TEXT_TRUNK = "Skipping generating seed question due to invalid text chunk." + INVALID_QUESTION = "Invalid seed question: {0}" + INVALID_ANSWER = "Invalid answer: {0}" + + +ValidationResult = namedtuple("ValidationResult", ["pass_validation", "reason_if_failed"]) def llm_call(connection, model, prompt, response_format="text"): if isinstance(connection, AzureOpenAIConnection): return aoai_chat( - connection=connection, - prompt=prompt, - deployment_name=model, - response_format={"type": response_format} + connection=connection, prompt=prompt, deployment_name=model, response_format={"type": response_format} ) elif isinstance(connection, OpenAIConnection): - return openai_chat( - connection=connection, - prompt=prompt, - model=model, - response_format={"type": response_format} - ) + return openai_chat(connection=connection, prompt=prompt, model=model, response_format={"type": response_format}) def get_question_type(testset_distribution) -> str: @@ -48,32 +58,30 @@ def get_question_type(testset_distribution) -> str: return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) -def is_valid_ground_truth(connection, model, prompt, ground_truth: str): - answer = llm_call(connection, model, prompt) +def get_ground_truth_validation_res(connection, model, prompt, ground_truth: str): + rsp = llm_call(connection, model, prompt) return retrieve_verdict_and_print_reason( - answer=answer, validate_obj_name=ValidateObj.GROUNDTRUTH, validate_obj=ground_truth + rsp=rsp, validate_obj_name=ValidateObj.GROUND_TRUTH, validate_obj=ground_truth ) -def is_valid_question(connection, model, prompt, question: str): - answer = llm_call(connection, model, prompt, "json_object") - return retrieve_verdict_and_print_reason( - answer=answer, validate_obj_name=ValidateObj.QUESTION, validate_obj=question - ) +def get_question_validation_res(connection, model, prompt, question: str, response_format: ResponseFormat): + rsp = llm_call(connection, model, prompt, response_format) + return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) -def is_valid_text_trunk(connection, model, prompt, context: str): - answer = llm_call(connection, model, prompt, "json_object") - return retrieve_verdict_and_print_reason( - answer=answer, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context - ) +def get_text_trunk_validation_res(connection, model, prompt, context: str, response_format: ResponseFormat): + rsp = llm_call(connection, model, prompt, response_format) + return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context) -def retrieve_verdict_and_print_reason(answer: str, validate_obj_name: str, validate_obj: str) -> bool: +def retrieve_verdict_and_print_reason(rsp: str, validate_obj_name: str, validate_obj: str) -> ValidationResult: try: - data = json.loads(answer) + # It is possible that even the response format is required as json, the response still contains ```json\n + rsp = re.sub(r"```json\n?|```", "", rsp) + data = json.loads(rsp) except json.decoder.JSONDecodeError: - print("llm failed to return the verdict and reason in correct json format.") + print(ErrorMsg.INVALID_JSON_FORMAT.format(rsp)) data = None if data and isinstance(data, dict) and "verdict" in data and "reason" in data: @@ -82,13 +90,13 @@ def retrieve_verdict_and_print_reason(answer: str, validate_obj_name: str, valid reason = data["reason"] print(f"Is valid {validate_obj_name}: {verdict}\nReason: {reason}") if verdict == "yes": - return True + return ValidationResult(True, "") elif verdict == "no": - return False + return ValidationResult(False, reason) else: print(f"Unexpected llm response to validate {validate_obj_name}: {validate_obj}") - return False + return ValidationResult(False, ErrorMsg.INVALID_JSON_FORMAT.format(rsp)) def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): @@ -103,7 +111,7 @@ def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): def generate_question( - connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None + connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None ): if question_type == QuestionType.SIMPLE: return seed_question diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py index 15752deb25a..0b8a01be866 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import is_valid_text_trunk, llm_call +from utils import ErrorMsg, ResponseFormat, get_text_trunk_validation_res, llm_call from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -13,17 +13,23 @@ def validate_and_generate_seed_question( validate_text_trunk_prompt: str, seed_question_prompt: str, context: str = None, + response_format: str = ResponseFormat.JSON, ): """ 1. Validates the given text chunk. 2. Generates a seed question based on the given prompts. Returns: - str: The generated seed question. + dict: The generated seed question and text trunk validation result. """ - if not is_valid_text_trunk(connection, model, validate_text_trunk_prompt, context): - print("Skipping generating seed question due to invalid text chunk.") - return "" + validation_res = get_text_trunk_validation_res( + connection, model, validate_text_trunk_prompt, context, response_format + ) + is_valid_text_trunk = validation_res.pass_validation + if not is_valid_text_trunk: + print(ErrorMsg.INVALID_TEXT_TRUNK) + print(f"yaodebug: {validation_res}") + return {"question": "", "validation_res": validation_res} seed_question = llm_call(connection, model, seed_question_prompt) - return seed_question + return {"question": seed_question, "validation_res": validation_res} diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py index 482d3e11bdf..8cc128ed1f0 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py +++ b/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import QuestionType, is_valid_question +from utils import ErrorMsg, QuestionType, ResponseFormat, get_question_validation_res from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -16,7 +16,8 @@ def validate_and_generate_test_question( validate_seed_question_prompt: str, # simple_ratio: float = 0.5, # reasoning_ratio: float = 0.25, - # conditional_ratio: float = 0.25 + # conditional_ratio: float = 0.25, + response_format: str = ResponseFormat.JSON, ): """ 1. Validates the given seed question. @@ -27,18 +28,26 @@ def validate_and_generate_test_question( """ # text trunk is not valid, seed question not generated. if not seed_question: - return {"question": "", "question_type": ""} - - is_valid_seed_question = is_valid_question(connection, model, validate_seed_question_prompt, seed_question) + return {"question": "", "question_type": "", "validation_res": None} + + validation_res = get_question_validation_res( + connection, model, validate_seed_question_prompt, seed_question, response_format + ) + is_valid_seed_question = validation_res.pass_validation + question = "" + question_type = "" + failed_reason = "" if not is_valid_seed_question: - print(f"Invalid seed question: {seed_question}") - return {"question": "", "question_type": ""} - - # TODO: add multi_context prompt (p3) - # TODO: add reasoning prompt and conditional prompt (p4) - # testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) - - # question_type = get_question_type(testset_distribution) - # question = generate_question(connection, model, question_type, seed_question) - - return {"question": seed_question, "question_type": QuestionType.SIMPLE} + failed_reason = ErrorMsg.INVALID_QUESTION.format(seed_question) + print(failed_reason) + else: + # TODO: add multi_context prompt (p3) + # TODO: add reasoning prompt and conditional prompt (p4) + # testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) + + # question_type = get_question_type(testset_distribution) + # question = generate_question(connection, model, question_type, seed_question) + question = seed_question + question_type = QuestionType.SIMPLE + + return {"question": question, "question_type": question_type, "validation_res": validation_res} diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py b/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py index 0d4ed665e7e..dc1498772b6 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py +++ b/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py @@ -1,6 +1,6 @@ from typing import Union -from utils import is_valid_ground_truth +from utils import ErrorMsg, get_ground_truth_validation_res from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -15,19 +15,22 @@ def validate_ground_truth( model: str, ground_truth: str, validate_ground_truth_prompt: str, -) -> str: +): """ 1. Validates the given ground truth. Returns: - str: The validated ground truth. + dict: The generated ground truth and its validation result. """ if not ground_truth: - return "" + return {"ground_truth": "", "validation_res": None} - is_valid_gt = is_valid_ground_truth(connection, model, validate_ground_truth_prompt, ground_truth) + validation_res = get_ground_truth_validation_res(connection, model, validate_ground_truth_prompt, ground_truth) + is_valid_gt = validation_res.pass_validation + failed_reason = "" if not is_valid_gt: - print(f"Invalid ground truth: {ground_truth}") - return "" - else: - return ground_truth + failed_reason = ErrorMsg.INVALID_ANSWER.format(ground_truth) + print(failed_reason) + ground_truth = "" + + return {"ground_truth": ground_truth, "validation_res": validation_res} diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py b/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py index 4ade6359ab0..7b085adb8d7 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py +++ b/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import QuestionType, is_valid_question +from utils import QuestionType, get_question_validation_res from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -28,7 +28,9 @@ def validate_test_question( # if question type is simple, the question is validated, no need to validate again. if question_type == QuestionType.SIMPLE: return question - is_valid_test_question = is_valid_question(connection, model, validate_question_prompt, question) + + validation_res = get_question_validation_res(connection, model, validate_question_prompt, question) + is_valid_test_question = validation_res.pass_validation if not is_valid_test_question: print(f"Invalid test question: {question}") return "" diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 index ddd11ba3b8f..63a259ea4df 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 +++ b/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 @@ -1,5 +1,5 @@ system: -Given a context, verdict if the provided context has information worthy of framing a question and give the reason. Output a json format with the reason and verdict. +Given a context, verdict if the provided context has information worthy of framing a question and give the reason. Output a JSON with the reason and verdict. The verdict can be either "yes" or "no", following these guidelines: 1. Verdict "yes" if: (1) context thoroughly delves into and explains concepts. @@ -11,7 +11,7 @@ The verdict can be either "yes" or "no", following these guidelines: (3) context that is shorter than five words. user: -Output a json format with both the reason and verdict. +Output a JSON with both the reason and verdict. Here are some examples: context: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time. diff --git a/examples/test_data_gen/src/utils/common.py b/examples/test_data_gen/src/utils/common.py index fad1425a685..8767e3e6ad9 100644 --- a/examples/test_data_gen/src/utils/common.py +++ b/examples/test_data_gen/src/utils/common.py @@ -38,11 +38,13 @@ def split_document(chunk_size, documents_folder, document_node_output): def clean_data_and_save(test_data_set: list, test_data_output_path: str): print("#### Start to clean the data.") - cleaned_data = [ - test_data - for test_data in test_data_set - if (test_data and all(val for key, val in test_data.items() if key.lower() != "line_number")) - ] + cleaned_data = [] + + for test_data in test_data_set: + if test_data and all( + val and val != "(Failed)" for key, val in test_data.items() if key.lower() != "line_number" + ): + cleaned_data.append(test_data) jsonl_str = "\n".join(map(json.dumps, cleaned_data)) with open(test_data_output_path, "wt") as text_file: From f4bdb4aa73b6dd7accc2f401c4dfc99b24c3ceb0 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 11:42:13 +0800 Subject: [PATCH 025/112] refactor structure and refine configs --- examples/test_data_gen/config.ini.example | 34 ++ .../src/document-nodes-test.jsonl | 293 ---------- .../src/test_data_gen_local/config.ini | 11 - .../test_data_gen_local/run_test_data_gen.py | 110 ---- .../src/test_data_gen_pipeline/__init__.py | 0 .../src/test_data_gen_pipeline/config.ini | 17 - .../run_test_data_gen_pipeline.py | 112 ---- examples/test_data_gen/src/utils/__init__.py | 0 .../{src => test_data_gen}/__init__.py | 0 .../construct_test_data_flow/flow.dag.yaml | 21 +- .../generate_debug_info.py | 0 .../generate_ground_truth.py | 0 .../generate_ground_truth_prompt.jinja2 | 0 .../construct_test_data_flow/requirements.txt | 0 .../seed_question_prompt.jinja2 | 0 .../construct_test_data_flow/utils.py | 1 + .../validate_and_generate_seed_question.py | 0 .../validate_and_generate_test_question.py | 0 .../validate_ground_truth.py | 0 .../validate_ground_truth_prompt.jinja2 | 0 .../validate_question_prompt.jinja2 | 0 .../validate_test_question.py | 0 .../validate_text_trunk_prompt.jinja2 | 0 .../requirements.txt | 0 .../requirements_cloud.txt} | 0 examples/test_data_gen/test_data_gen/run.py | 242 ++++++++ .../utils}/__init__.py | 0 .../{src => test_data_gen}/utils/common.py | 7 +- .../utils/components.py | 0 .../{src => test_data_gen}/utils/constants.py | 0 examples/test_data_gen/text-chunk-data.jsonl | 531 ------------------ 31 files changed, 293 insertions(+), 1086 deletions(-) create mode 100644 examples/test_data_gen/config.ini.example delete mode 100644 examples/test_data_gen/src/document-nodes-test.jsonl delete mode 100644 examples/test_data_gen/src/test_data_gen_local/config.ini delete mode 100644 examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py delete mode 100644 examples/test_data_gen/src/test_data_gen_pipeline/__init__.py delete mode 100644 examples/test_data_gen/src/test_data_gen_pipeline/config.ini delete mode 100644 examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py delete mode 100644 examples/test_data_gen/src/utils/__init__.py rename examples/test_data_gen/{src => test_data_gen}/__init__.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/flow.dag.yaml (90%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/generate_debug_info.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/generate_ground_truth.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/generate_ground_truth_prompt.jinja2 (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/requirements.txt (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/seed_question_prompt.jinja2 (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/utils.py (97%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_and_generate_seed_question.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_and_generate_test_question.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_ground_truth.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_ground_truth_prompt.jinja2 (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_question_prompt.jinja2 (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_test_question.py (100%) rename examples/test_data_gen/{src => test_data_gen}/construct_test_data_flow/validate_text_trunk_prompt.jinja2 (100%) rename examples/test_data_gen/{src/test_data_gen_local => test_data_gen}/requirements.txt (100%) rename examples/test_data_gen/{src/test_data_gen_pipeline/requirements.txt => test_data_gen/requirements_cloud.txt} (100%) create mode 100644 examples/test_data_gen/test_data_gen/run.py rename examples/test_data_gen/{src/test_data_gen_local => test_data_gen/utils}/__init__.py (100%) rename examples/test_data_gen/{src => test_data_gen}/utils/common.py (86%) rename examples/test_data_gen/{src => test_data_gen}/utils/components.py (100%) rename examples/test_data_gen/{src => test_data_gen}/utils/constants.py (100%) delete mode 100644 examples/test_data_gen/text-chunk-data.jsonl diff --git a/examples/test_data_gen/config.ini.example b/examples/test_data_gen/config.ini.example new file mode 100644 index 00000000000..0969c3dd6d1 --- /dev/null +++ b/examples/test_data_gen/config.ini.example @@ -0,0 +1,34 @@ +; config.ini +; This is a sample configuration file + +[DEFAULT] +; The DEFAULT section provides default values for all other sections. +; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. +; However, if you wish to bypass the document split process, simply provide the 'document_node_file', which is a JSONL file. +; When all these parameters are configured, the system will primarily use the 'document_node_file' +document_folder = "" +document_chunk_size = 1024 +document_node_file = "" + +; Test data gen flow configs +flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry +connection_name = "" + + +[LOCAL] +; This section is for local test data generation related configuration. +output_folder = "" +flow_batch_run_size = 10 + + +[CLOUD] +; This section is for cloud test data generation related configuration. +subscription_id = "" +resource_group = "" +workspace_name = "" +aml_cluster = "" + +; Parallel run step configs +prs_instance_count = 2 +prs_mini_batch_size = "10kb" +prs_max_concurrency_per_instance = 10 diff --git a/examples/test_data_gen/src/document-nodes-test.jsonl b/examples/test_data_gen/src/document-nodes-test.jsonl deleted file mode 100644 index 40996506dfe..00000000000 --- a/examples/test_data_gen/src/document-nodes-test.jsonl +++ /dev/null @@ -1,293 +0,0 @@ -{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow.", "document_node": "{\"id_\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b402c5d-538d-408b-9cb1-d66d47fffa40\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a51a60cd4ae560e102258e62ad38f93648f1d46243cb797a66704c23cd9ab80a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"text\": \"Add conditional control to a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\\n\\nThis guide will help you learn how to use activate config to add conditional control to your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`.", "document_node": "{\"id_\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15868ad6-c777-44b2-8e97-9be423ee1483\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ad88a6a9078f088ce0a7ed654c73052d2178573eb746ac2c4162ef58f96634e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"text\": \"Prerequisites\\n\\nPlease ensure that your promptflow version is greater than `0.1.0b5`.\", \"start_char_idx\": 2, \"end_char_idx\": 86, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::", "document_node": "{\"id_\": \"31293458-8cee-4967-8348-4114666ad247\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"77279509-65c8-4fa1-9ced-eff19c2bd279\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"85d4f1ef1cd02a2a25836c3e629e10e19b777a402ee672b9021ae20a3cd5627d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"text\": \"Usage\\n\\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\\n\\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\\n\\n::::{tab-set}\\n:::{tab-item} YAML\\n:sync: YAML\\n\\nYou can add activate config in the node section of flow yaml.\\n```yaml\\nactivate:\\n when: ${node.output}\\n is: true\\n```\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\\n!visual_editor\\n\\n- Click on the `Activation config` section in the node you want to add and fill in the values for \\\"when\\\" and \\\"is\\\".\\n!activate_config\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1154, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed", "document_node": "{\"id_\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dd45d45-00c4-4909-a54a-4b03f741623a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b462c2a1e9f20e051210c996e39d721335d61d44c64a788cae8cb40292e9d443\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"text\": \"Further details and important notes\\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\\n\\n !provide_default_value\\n\\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\\n\\n !output_bypassed\\n\\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \\\"Bypassed\\\", as shown in the figure below Show. There are three situations in which a node is bypassed.\\n\\n !bypassed_nodes\\n\\n\\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\\n\\n !activate_condition_always_met\\n\\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\\n\\n !activate_when_bypassed\\n\\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\\n\\n !dependencies_bypassed\", \"start_char_idx\": 2, \"end_char_idx\": 1434, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example", "document_node": "{\"id_\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c3e1eb6-23bf-44d1-bda4-5d37c208ee12\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c2d44a764f3b69bd15d3a78bec6b1601edecc6dfbf80ae99d4a6572eec2b15e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"text\": \"Example flow\\n\\nLet's illustrate how to use activate config with practical examples.\\n\\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\\n- Switch scenario: Explore conditional flow for switch scenarios. View Example\", \"start_char_idx\": 2, \"end_char_idx\": 260, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\n- Run and evaluate a flow", "document_node": "{\"id_\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"782a7b53-7c3c-448c-8908-a78835c5561f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"80d3825fe6697eff08a6a2e7aec7eef79ea6fec62bcbb9e6d0013befe8c13811\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"text\": \"Next steps\\n\\n- Run and evaluate a flow\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to construct test data based on documents\nThis guide will help to construct test data based on the provided documents.\nThe test data construction process contains three steps:\n- Split documents to smaller trunks.\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\n- Collect all the test data and remove empty values.", "document_node": "{\"id_\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d762c45d-76f8-44b7-ad01-f762c3b68201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fedab640d7be99800a8d2565a8cb7ec2ab9a551623a2612ab024014c2a0c6269\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"text\": \"How to construct test data based on documents\\nThis guide will help to construct test data based on the provided documents.\\nThe test data construction process contains three steps:\\n- Split documents to smaller trunks.\\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\\n- Collect all the test data and remove empty values.\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data preprocess\nEnter `test_data_gen_local` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c3acac60-fcab-445a-a4e2-189036d3baea\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"875f62cb506a3703f747a728b452b208ee7384cc39c747e00d1a5155dbb0ccbf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"text\": \"Data preprocess\\nEnter `test_data_gen_local` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 145, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get started\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\n> [!Note] This step can be skipped if you just want to have a try.\n\n- Enter test_data_gen_local folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen.py\n ```\n - The generated test data would be a data jsonl file with path you configured in `config.ini`", "document_node": "{\"id_\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dfc13dfd-4b2e-4016-a57a-2d2306d8e5d4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b6ad8f04373fe87782c782471ea659a4fd0e338f74b248a7de9aded5eced04c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"text\": \"Get started\\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\\n> [!Note] This step can be skipped if you just want to have a try.\\n\\n- Enter test_data_gen_local folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen.py\\n ```\\n - The generated test data would be a data jsonl file with path you configured in `config.ini`\", \"start_char_idx\": 2, \"end_char_idx\": 489, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Cloud\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.", "document_node": "{\"id_\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e5582dc9-2527-4689-a66b-3499f60d39ec\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aab6ff042514dbdc1c619bf071e11425c08125c6f6f889eb0c78445e1ddf3b34\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"text\": \"Cloud\\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.\", \"start_char_idx\": 2, \"end_char_idx\": 95, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"880d9550-3b75-4405-b690-dac4ffff2d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ffa284d6ce0438755afec9d24989afc353c5ab2bdee44cfe9dfcfa9287fa312f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"text\": \"Prerequisites\\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 146, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get started\n- Enter test_data_gen_pipeline folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen_pipeline.py\n ```\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.", "document_node": "{\"id_\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"920d1a8d-54b7-495d-bba0-92c616963af6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff72434cf5652a1df86ae0d8e0a4d1cdb20755160a3b5b04c210cc3d180afe4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"text\": \"Get started\\n- Enter test_data_gen_pipeline folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen_pipeline.py\\n ```\\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash", "document_node": "{\"id_\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"985feda6-5910-4344-8ac2-8e1f004066b7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7566d96cdda7049299b58e66d25859f99137724b7dcaee863800e26459f95290\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"text\": \"Deploy a flow using development server\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nWe are going to use the web-classification as\\nan example to show how to deploy a flow.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \\nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \\nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \\nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \\n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \\nvalue as a fallback.\\n\\n\\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1340, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::", "document_node": "{\"id_\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4726d80-ea7e-4fba-9613-db83617bb882\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac3a543e1dceee101173b9bc7ff893ee9fb5a9ceae85efa8194cdc97b790151a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"text\": \"Serve the flow at localhost:8080\\npf flow serve --source --port 8080 --host localhost\\n```\\n\\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\\n\\n!img\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\nIn visual editor, choose:\\n!img\\nthen choose format:\\n!img\\nthen in yaml editor:\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 364, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::", "document_node": "{\"id_\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5920919b-f0f6-4e82-8f36-b0ed794adca7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3a597bc0d35a21864ac97adf0631fa8b80c3c91c6f9cfdbf2792054289656b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"text\": \"Test endpoint\\n::::{tab-set}\\n:::{tab-item} Bash\\nYou could open another terminal to test the endpoint with the following command:\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\\n:::\\n:::{tab-item} PowerShell\\nYou could open another terminal to test the endpoint with the following command:\\n```powershell\\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -Method POST -ContentType \\\"application/json\\\"\\n```\\n:::\\n:::{tab-item} Test Page\\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 778, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ebc2e916-88ef-49b3-95f7-c181df18e83a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45ffa4d534f92a3990305fa76c49e9bc990763b6a85a443546545b8853581739\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using docker.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image.", "document_node": "{\"id_\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"001a5af0-2cb9-4089-997c-197892a18fd7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3cb96282cb3a51734f72174afeb7eb4676623f5801355e4cc3bcf5bf4f520338\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"text\": \"Deploy a flow using Docker\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are two steps to deploy a flow using docker:\\n1. Build the flow as docker format.\\n2. Build and run the docker image.\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf2f3ae5-ba72-4beb-86a4-1bc49436e1da\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0057da34d9137e38191046124bf42bcf8c1c1f4a027da0f73bac07c083ee4554\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1ae36579-078a-4568-8aba-c5dda9d14b7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8c279a743b10f1167ab4728059c1d90e3b2b5415f812715b657fd620826065ad\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.", "document_node": "{\"id_\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dc49828-c68f-4468-9df7-b79c065f957e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a10de6a73f84be1c1b016021afada237667a01c4928fd4fe49dd16f6339cc2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"text\": \"Deploy with Docker\\nWe are going to use the web-classification as\\nan example to show how to deploy with docker.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\", \"start_char_idx\": 2, \"end_char_idx\": 244, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cf6e2bc6-78d1-49ec-a697-cb2842d6fe1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ab5f3b806ff2c792734f1c1ad6c7bb6e3568b15939996aaab1650926bd7113b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"text\": \"Build a flow as docker format app\\n\\nUse the command below to build a flow as docker format app:\\n\\n```bash\\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\\n```\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 283, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```", "document_node": "{\"id_\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"787280bc-ae47-42e9-b7bb-2cf6d722902f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"025c08762a5530fe9b4d08fc2ee90bd910c36f27c24c6b442a3396d375a4c9c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\\n\\nRun the command below to build image:\\n\\n```bash\\ndocker build dist -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container.", "document_node": "{\"id_\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24c4f02a-f692-45ae-b6db-af8952922b50\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305bc2ac535b78373a93bbec09010ac6f2e3a0c5eda71ea5520198308366bd88\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"text\": \"Run Docker image\\n\\nRun the docker image will start a service to serve the flow inside the container.\", \"start_char_idx\": 2, \"end_char_idx\": 101, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4d1cbd08-9a15-4dae-9977-1a5b3e0e96e3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"454d361baede9825a6b5a25526bb0659e713e58685077d7448585205f0b99fc2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash", "document_node": "{\"id_\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d4a6eb86-2f08-48ea-a19d-db7442b672a3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2a9c5bb24d9dc83e164398fda42138afca7298371035a2e2e6b5e79b9586e95\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"text\": \"Run with `docker run`\\n\\nYou can run the docker image directly set via below commands:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 94, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```", "document_node": "{\"id_\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4937a2c8-60fb-4b10-ad90-64e2e0ad9203\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5db95208bb6ad14c49e70ef284d9838cf1c03aec34a0529b167858504277263\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"text\": \"The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 196, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```", "document_node": "{\"id_\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"094daa74-2704-419b-88a3-d90b6b14be78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d5595bcd64f47bff9d713811f8ea973e1e144428cdeba4c28f2c6e35f373537d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"text\": \"Test the endpoint\\nAfter start the service, you can use curl to test it:\\n\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 249, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbb19bfc-117b-4108-b0f0-782008d0d6f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d32afb6a7a32f2d7209c5e9c81a494466c7b79c8aec3991f80e2c38b7c7ed429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment.", "document_node": "{\"id_\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35233e62-7f70-4f02-bcb0-266eb8bab18d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edb6e94975ce9597a7289e364191cb2f0d9ccc41c1dc29ed10078ed5bffe6201\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"text\": \"Deploy a flow using Kubernetes\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are four steps to deploy a flow using Kubernetes:\\n1. Build the flow as docker format.\\n2. Build the docker image.\\n3. Create Kubernetes deployment yaml.\\n4. Apply the deployment.\", \"start_char_idx\": 2, \"end_char_idx\": 329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash", "document_node": "{\"id_\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"03b68070-8b3a-4e97-b6b5-2efdbd897d0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c32dac478d5c6812b1c1b508fd58be363fd98dc2b93fa1629c5780685a5395ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote that all dependent connections must be created before building as docker.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 163, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9d0ff802-5f7e-4d38-9298-2fe1d72d162a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28da9c8ae14ba1d288700ff08b67f3c64af26e9c9260c5acbe9d3bfce4f0a81c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 490, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a465868-961b-42fa-aff4-023aec92284b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"737ada3363594778b97169c88d91adcd82c3852d6ad94c3afededb851566d7e9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.", "document_node": "{\"id_\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cd6a5ee9-be8a-4cd3-a609-588043b8a5dc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb90193d094243e3f362f8f4834d27aae9ae1cc9c64e9cb898666ef5efcd7a22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"text\": \"Deploy with Kubernetes\\nWe are going to use the web-classification as\\nan example to show how to deploy with Kubernetes.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.\", \"start_char_idx\": 2, \"end_char_idx\": 494, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```", "document_node": "{\"id_\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca057cce-ae41-4870-86c6-2a7e11df6884\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf0826466e0b7135f7fa8f52748ebd1e0bf36b6c9b70923142f15679305f1509\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\\n\\nThen run the command below:\\n\\n```bash\\ncd \\ndocker build . -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 266, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```", "document_node": "{\"id_\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"416b4a60-5b95-4610-8818-5c0a950e70b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39fd3d4d93952fc682966479183abf5b004eb51f53bc7a39a608b97d417fa280\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"text\": \"Create Kubernetes deployment yaml.\\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\\n\\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\\n```bash\\nencoded_secret=$(echo -n | base64)\\n```\\n\\n```yaml\\n---\\nkind: Namespace\\napiVersion: v1\\nmetadata:\\n name: \\n---\\napiVersion: v1\\nkind: Secret\\nmetadata:\\n name: open-ai-connection-api-key\\n namespace: \\ntype: Opaque\\ndata:\\n open-ai-connection-api-key: \\n---\\napiVersion: v1\\nkind: Service\\nmetadata:\\n name: web-classification-service\\n namespace: \\nspec:\\n type: NodePort\\n ports:\\n - name: http\\n port: 8080\\n targetPort: 8080\\n nodePort: 30123\\n selector:\\n app: web-classification-serve-app\\n---\\napiVersion: apps/v1\\nkind: Deployment\\nmetadata:\\n name: web-classification-serve-app\\n namespace: \\nspec:\\n selector:\\n matchLabels:\\n app: web-classification-serve-app\\n template:\\n metadata:\\n labels:\\n app: web-classification-serve-app\\n spec:\\n containers:\\n - name: web-classification-serve-container\\n image: \\n imagePullPolicy: Never\\n ports:\\n - containerPort: 8080\\n env:\\n - name: OPEN_AI_CONNECTION_API_KEY\\n valueFrom:\\n secretKeyRef:\\n name: open-ai-connection-api-key\\n key: open-ai-connection-api-key\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1691, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.", "document_node": "{\"id_\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2f87d0-7ce6-424f-baf5-9a719bd9e6dd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"477a540f66a6f1ee65bfd60768d2a3d59c1dcadacee96a857fe7f25753276d75\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"text\": \"Apply the deployment.\\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\\n```bash\\nminikube start\\n```\\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\\n```bash\\nkubectl apply -f deployment.yaml\\n```\\nThis command will create the necessary pods to run your application within the cluster.\\n\\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.\", \"start_char_idx\": 2, \"end_char_idx\": 697, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```", "document_node": "{\"id_\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e957261-66c9-478e-a059-e80a3e8b0978\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b6370003e6a7da8b9a3332e4ffb0c781dac39e5cfb2e2ceb896790c8a4128be4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"text\": \"Retrieve flow service logs of the container\\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\\n\\n```bash\\nkubectl -n logs \\n```\", \"start_char_idx\": 2, \"end_char_idx\": 281, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fc445c62-3acb-4049-8230-38c9d8466d0b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8215b76f0bcab42a64d833c86863fbdb33dcc95da1fb59674394281d6c6fa40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```", "document_node": "{\"id_\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"272125df-0bcb-4bd6-bf09-c0ec657b16e6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50a786047950de8aa8f76dfa723527bb5c7e34deb5595b227792230410c0f3c1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"text\": \"Test the endpoint\\n- Option1:\\n\\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\\n To achieve this, execute the following command:\\n\\n ```bash\\n kubectl port-forward : -n \\n ```\\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\\n\\n- Option2:\\n\\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\\n\\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \\n\\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1405, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.", "document_node": "{\"id_\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c90f24c2-70ef-4f4a-bec5-944c963c0017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f33e56b02f183c64dfe8e88bb3d10c17054eb93b672d3dfc9f7b81353b318734\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"text\": \"Next steps\\n- Try the example here.\", \"start_char_idx\": 2, \"end_char_idx\": 36, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.", "document_node": "{\"id_\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"78c930c3-0d07-47fa-bcb4-c05ee6801638\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce667521e60986a068e5688e6f7084f84281c241bc239aeacd088d8815f5d142\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"text\": \"Distribute flow as executable app\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nWe are going to use the web-classification as\\nan example to show how to distribute flow as executable app with Pyinstaller.\\n\\n\\nPlease ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \\n\\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.\", \"start_char_idx\": 2, \"end_char_idx\": 1262, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash", "document_node": "{\"id_\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"889137df-2303-4e28-9e25-af03a3dade9a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"788efa4a3e263596c0e89a318492f454d61b1947a3249b5817814acecccddf69\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"text\": \"Build a flow as executable format\\nNote that all dependent connections must be created before building as executable.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```", "document_node": "{\"id_\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b8cb107-8895-47b3-bb7b-4afda0994fcf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a5b966cba851cc99e639ac17d4e9ce03f6d8ec9b948b2b2ec507aa7e1a1fa00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as executable format:\\n```bash\\npf flow build --source --output --format executable\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 298, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files.", "document_node": "{\"id_\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cbcb9eaf-2132-477b-8703-ab3179413b0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60e4cbfdadc24044a4f6ff9eff16829666816426530e507bf35ac475af6e80ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"text\": \"Executable format folder structure\\n\\nExported files & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files.\\n- connections: the folder contains yaml files to create all related connections.\\n- app.py: the entry file is included as the entry point for the bundled application.\\n- app.spec: the spec file tells PyInstaller how to process your script.\\n- main.py: it will start streamlit service and be called by the entry file.\\n- settings.json: a json file to store the settings of the executable application.\\n- build: a folder contains various log and working files.\\n- dist: a folder contains the executable application.\\n- README.md: Simple introduction of the files.\", \"start_char_idx\": 2, \"end_char_idx\": 733, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```", "document_node": "{\"id_\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8754ca46-b358-442e-85aa-2dd01a1c60b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"525024450d56483fc20362c341d7af6062113e5f8fe6518a8b279a5c130d6ff3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"text\": \"A template script of the entry file\\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \\n\\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\\n\\n```python\\nimport os\\nimport sys\\n\\nfrom promptflow._cli._pf._connection import create_connection\\nfrom streamlit.web import cli as st_cli\\nfrom streamlit.runtime import exists\\n\\nfrom main import start\\n\\ndef is_yaml_file(file_path):\\n _, file_extension = os.path.splitext(file_path)\\n return file_extension.lower() in ('.yaml', '.yml')\\n\\ndef create_connections(directory_path) -> None:\\n for root, dirs, files in os.walk(directory_path):\\n for file in files:\\n file_path = os.path.join(root, file)\\n if is_yaml_file(file_path):\\n create_connection(file_path)\\n\\n\\nif __name__ == \\\"__main__\\\":\\n create_connections(os.path.join(os.path.dirname(__file__), \\\"connections\\\"))\\n if exists():\\n start()\\n else:\\n main_script = os.path.join(os.path.dirname(__file__), \\\"main.py\\\")\\n sys.argv = [\\\"streamlit\\\", \\\"run\\\", main_script, \\\"--global.developmentMode=false\\\"]\\n st_cli.main(prog_name=\\\"streamlit\\\")\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1486, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec", "document_node": "{\"id_\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35fb4943-f149-41fa-bdd4-d7e134bf38ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3359e5ab1140c765b2cec249fad745ee49bf26f68fb798200109fd048f8ea886\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"text\": \"A template script of the spec file\\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\\n\\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\\n\\n```spec\", \"start_char_idx\": 2, \"end_char_idx\": 626, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```", "document_node": "{\"id_\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e2b8a188-7744-48aa-bd3e-88622db05d16\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92c55ce053208bb4f5a6a40a6658a2620ec99440bbcb2e2984a892b3ab2b41ec\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"text\": \"-*- mode: python ; coding: utf-8 -*-\\nfrom PyInstaller.utils.hooks import collect_data_files\\nfrom PyInstaller.utils.hooks import copy_metadata\\n\\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\\ndatas += collect_data_files('streamlit')\\ndatas += copy_metadata('streamlit')\\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\\ndatas += copy_metadata('keyrings.alt')\\ndatas += collect_data_files('streamlit_quill')\\n\\nblock_cipher = None\\n\\n\\na = Analysis(\\n ['app.py', 'main.py'],\\n pathex=[],\\n binaries=[],\\n datas=datas,\\n hiddenimports=['bs4'],\\n hookspath=[],\\n hooksconfig={},\\n runtime_hooks=[],\\n excludes=[],\\n win_no_prefer_redirects=False,\\n win_private_assemblies=False,\\n cipher=block_cipher,\\n noarchive=False,\\n)\\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\\n\\nexe = EXE(\\n pyz,\\n a.scripts,\\n a.binaries,\\n a.zipfiles,\\n a.datas,\\n [],\\n name='app',\\n debug=False,\\n bootloader_ignore_signals=False,\\n strip=False,\\n upx=True,\\n upx_exclude=[],\\n runtime_tmpdir=None,\\n console=True,\\n disable_windowed_traceback=False,\\n argv_emulation=False,\\n target_arch=None,\\n codesign_identity=None,\\n entitlements_file=None,\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1331, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.", "document_node": "{\"id_\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbbf6b9c-6c93-4225-9464-811c74b323b1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"137b06713f5e2940b2fe428d41780bb47007f0e7ec4af0aae52c6ed2a843f992\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"text\": \"The bundled application using Pyinstaller\\nOnce you've build a flow as executable format following Build a flow as executable format.\\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```", "document_node": "{\"id_\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0dd26999-3784-4781-b921-16dc8238be64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554ae32ca1c480322848743e9c6da4fd7418108c6046d6cac9f2b84fba6edd71\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 501, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).", "document_node": "{\"id_\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c2d3b808-b23f-43eb-a47c-1222042cef68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9e38dad6f79b85483297a2e961c7074d5eb7b33e144a833dfeb034ffc8d6380\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"text\": \"Test the endpoint\\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \\n\\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\\n\\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\\n\\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).\", \"start_char_idx\": 2, \"end_char_idx\": 819, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.", "document_node": "{\"id_\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c33c3b24-6d2f-4008-886e-5f909d48d67f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c51e0c6b8fd6ab482b88267abb541c19a26e8a5ace41312d12b6934cfc961ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"text\": \"Known issues\\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.\", \"start_char_idx\": 2, \"end_char_idx\": 162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here", "document_node": "{\"id_\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a01c5abe-5e5a-4ddb-add2-e3860e52b7cc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e568ec67bd14372ad8610019228abfcab0577cf33fc2d5c498a88ba6889ba595\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"text\": \"Next steps\\n- Try the example here\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fedee87-d831-42e5-8868-b687b8669cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7fee890cde8a5e564cd8a0ac6f8e2e91acb42d8f07a7afb781d3e7fe3abad5de\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"text\": \"Develop chat flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 314, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"459ea5a0-07b2-4018-9d73-f5c12560a9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"34672e2e9b5d672a905e718c868c88a5dc1f874f92b883d54f30ea8c8bbc7251\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"text\": \"Flow input data\\n\\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\\n\\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\\n\\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\\n \\n An example of chat history:\\n ```python\\n [\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What types of container software there are?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"There are several types of container software available, including: Docker, Kubernetes\\\"}},\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What's the different between them?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\\\"}},\\n ] \\n ```\\n\\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\\n```yaml\\ninputs:\\n chat_history:\\n type: list\\n is_chat_history: true\\n default: []\\n question:\\n type: string\\n is_chat_input: true\\n default: What is ChatGPT?\\n```\\n\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 1811, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19e1d3da-0011-44c6-842e-f43872513fee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7174bd166b0fb96b0c3c56f110b7bf6b469e98368c15514bfc18c5bda0333ced\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow.", "document_node": "{\"id_\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec04b974-2730-40eb-b576-9ff5b98ec67a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f683434028ff51d70bcc3e19d09c958ea5fbac263b5b572a16e8cfcc6dfe623\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\\n\\nFor more information see chain your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```", "document_node": "{\"id_\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13f31c7e-48b2-4c8b-a22c-75a2ed4ef4a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09947add90687052194ef8af3b2f29e05eae203b6f2be62d68b64ed4e0c165e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"text\": \"Set flow output\\n\\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\\n\\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\\n\\n```yaml\\noutputs:\\n answer:\\n type: string\\n reference: ${chat.output}\\n is_chat_output: true\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 453, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.", "document_node": "{\"id_\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8155fe6d-e44d-4b32-a92d-cfd53d2d1dc9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"050307129fb74fe69bb453b44fb4578c009429623df62e027e90bd000d14aea4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"text\": \"Develop evaluation flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\\n\\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\\n- `Inputs/Outputs definition`\\n- `Nodes`\\n- `Chain nodes in a flow`\\n\\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.", "document_node": "{\"id_\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9af9790b-674a-4a32-b26d-76d74f80c201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30a482680af6d77ff4a32b07e7e70496af7d8e659d41e9ddd9bc1a3d2a9e799c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"text\": \"Evaluation flow example\\n\\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.\", \"start_char_idx\": 2, \"end_char_idx\": 439, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.", "document_node": "{\"id_\": \"f67eae57-2228-4768-bf9e-752182255315\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a928698-f22c-4012-85c2-e736a3205a32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"806a38502591403dda37598c10e796b0d0b5c7da92670db5caa94bd4059efa78\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"text\": \"Flow inputs\\n\\nThe flow `eval-classification-accuracy` contains two inputs:\\n\\n```yaml\\ninputs:\\n groundtruth:\\n type: string\\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\\n default: APP\\n prediction:\\n type: string\\n description: The actual predicted outputs that your flow produces.\\n default: APP\\n```\\n\\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \\n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\\n\\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1174, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.", "document_node": "{\"id_\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00b01149-18e5-4fb6-af7c-d1074b90fccb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de34c0d3cae520dc7074bb45e7e48909c31b019d26a7cb740829def7c0c2acdd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"text\": \"Aggregation node\\n\\n\\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\\n\\n```yaml\\n- name: grade\\n type: python\\n source:\\n type: code\\n path: grade.py\\n inputs:\\n groundtruth: ${inputs.groundtruth}\\n prediction: ${inputs.prediction}\\n```\\n\\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\\n\\n```python\\nfrom promptflow import tool\\n\\n@tool\\ndef grade(groundtruth: str, prediction: str):\\n return \\\"Correct\\\" if groundtruth.lower() == prediction.lower() else \\\"Incorrect\\\"\\n```\\n\\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\\n1. It has an attribute `aggregation` set to be `true`.\\n\\n```yaml\\n- name: calculate_accuracy\\n type: python\\n source:\\n type: code\\n path: calculate_accuracy.py\\n inputs:\\n grades: ${grade.output}\\n aggregation: true # Add this attribute to make it an aggregation node\\n```\\n\\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef calculate_accuracy(grades: List[str]):\\n result = []\\n for index in range(len(grades)):\\n grade = grades[index]\\n result.append(grade)\\n\\n # calculate accuracy for each variant\\n accuracy = round((result.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(\\\"accuracy\\\", accuracy)\\n\\n return result\\n```\\n\\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Channel\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\n\\n And we provides a data file like this:\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Channel\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nThen the `grades` value would be `[\\\"Correct\\\", \\\"Correct\\\", \\\"Incorrect\\\"]`, and the final accuracy is `0.67`. \\n\\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.\", \"start_char_idx\": 2, \"end_char_idx\": 2278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`.", "document_node": "{\"id_\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"952a2672-5398-4540-b942-4d7b4e729b92\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"822605742d13841acd10ffcea5db1d1a13e3e30e09dbb36b3e51a8d80046c79e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"text\": \"More about the list parameter\\n\\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\\n\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\\n\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nIn this case, the `grades` value would be `[\\\"Correct\\\", \\\"Incorrect\\\"]` and the accuracy is `0.5`.\", \"start_char_idx\": 2, \"end_char_idx\": 920, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img", "document_node": "{\"id_\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f7fa17f-8dee-470a-916d-e55d9fe11f1e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60ff341156316a69a77efdcace6fd85fa977b463e106c0110ba68ba78da5f0b5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"text\": \"How to set aggregation node in VS Code Extention\\n\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img", "document_node": "{\"id_\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a7d7d4cd-91ab-4d18-9812-73abab2aaac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62f9779b95c01ecabbbe5cdcda006b117a8dd30ff024f26bd9ec2d33ad4aa7f6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"text\": \"How to log metrics\\n:::{admonition} Limitation\\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\\n:::\\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \\n\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef example_log_metrics(grades: List[str]):\\n # this node is an aggregation node so it accepts a list of grades\\n metric_key = \\\"accuracy\\\"\\n metric_value = round((grades.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(metric_key, metric_value)\\n```\\n\\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 777, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"242a77a2-a306-40bf-93d7-cd6878f5b9bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97d57345e8b5efdb1c430e93e2262ab8995b9b9b3fbf17e9738b3decaf201c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"text\": \"Develop standard flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 322, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types.", "document_node": "{\"id_\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9635de74-544b-4e42-b80e-66f4a9558c00\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668b015e6c989c7d86e3dfcad898c06c44f445fe96bd6d6fccf909a044c1ede0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"text\": \"Flow input data\\nThe flow input data is the data that you want to process in your flow. \\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a flow input in inputs section of flow yaml.\\n```yaml\\ninputs:\\n url:\\n type: string\\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \\nand the input value.\\n\\n!flow_input\\n:::\\n\\n::::\\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\\nFor more input types in a python tool, please refer to Input types.\", \"start_char_idx\": 2, \"end_char_idx\": 757, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.", "document_node": "{\"id_\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"919ca595-35ff-4dba-8a31-26b416b7e3ab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0cf6fa20af96fe27dfaf6ee9484693e4513ea19ec3d3ef8e6b56ebcb0ecaea23\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\", \"start_char_idx\": 2, \"end_char_idx\": 212, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::", "document_node": "{\"id_\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c60c3d4-098c-4952-ba3b-0de0506f55f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0bcdc43c78e08ebcf9feadfbe7d897b9998f6b922626ed3c1870d182634403c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"text\": \"Add tool as your need\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\\n\\n!add_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool", "document_node": "{\"id_\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fdf5dd30-8270-4fee-aa1a-abcfbcbb512b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c3fadc7c5b72b98e4ba684a95f971986f4df0034a0a614271c2ffc78074df271\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"text\": \"Edit tool\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\\n\\n```python\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::", "document_node": "{\"id_\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b15324bb-86ed-44cb-bd91-796bc99a3242\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b2175984579bdcc522aadd3d3f03eac2d874f191c3230e9d5f99a7406f02ab54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"text\": \"The inputs section will change based on the arguments of the tool function, after you save the code\\n@tool\\ndef my_python_tool(input1: str) -> str:\\n return 'hello ' + input1\\n```\\n\\nWe also provide an LLM tool prompt below.\\n\\n```jinja\\nPlease summarize the following text in one paragraph. 100 words.\\nDo not add any information that is not in the text.\\nText: {{text}}\\nSummary:\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \\nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \\ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\\n!edit_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 938, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details.", "document_node": "{\"id_\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8372ff3d-7692-45b9-ac7d-81f0f40101b5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fdbc523c40c6af31143083203d50b7b08d2ea8520099eeda080947118eab3d00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"text\": \"Create connection\\nPlease refer to the Create necessary connections for details.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.", "document_node": "{\"id_\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01934a78-1481-496a-8449-4e8fe6e4a85f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"17c34f9a2db75c40a67d3f3bb44546b8ffe352ba6f837e324a7955cbf41877b2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\", \"start_char_idx\": 2, \"end_char_idx\": 114, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```", "document_node": "{\"id_\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86c4ea6f-359c-484e-b68e-431c7adcf5c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45184bbd7413f02695ec0459bc753bb0bc538058b5e19dc48636c3bb7e15f50c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"text\": \"Define LLM node interface\\nLLM node has only one output, the completion given by LLM provider.\\n\\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \\nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \\ntemplating language. For example:\\n\\n```jinja\\nYour task is to classify a given url into one of the following types:\\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\\nThe classification will be based on the url, the webpage text content summary, or both.\\n\\nHere are a few examples:\\n{% for ex in examples %}\\nURL: {{ex.url}}\\nText content: {{ex.text_content}}\\nOUTPUT:\\n{\\\"category\\\": \\\"{{ex.category}}\\\", \\\"evidence\\\": \\\"{{ex.evidence}}\\\"}\\n\\n{% endfor %}\\n\\nFor a given URL : {{url}}, and text content: {{text_content}}.\\nClassify above url to complete the category and indicate evidence.\\nOUTPUT:\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 958, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```", "document_node": "{\"id_\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0d6a1e23-9c61-456e-b5f8-6646774e7517\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7098a85fc27d133c1dd382abf3c7c82f3704b115745129d0b4c63e59891bbcb6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"text\": \"Define Python node interface\\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \\nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\\nFor example:\\n\\n```python\\nimport json\\nfrom promptflow import tool\\n\\n@tool\\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\\n try:\\n print(input_str2)\\n return json.loads(input_str)\\n except Exception as e:\\n print(\\\"input is not valid, error: {}\\\".format(e))\\n return {\\\"category\\\": \\\"None\\\", \\\"evidence\\\": \\\"None\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 595, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together.", "document_node": "{\"id_\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2b337a61-282c-4aa0-8cc2-a303344a3a87\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"72154d54360f4b5a82884b63734ac5365a69ed681123ba1e32eb8718628ee58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"text\": \"Link nodes together\\nAfter the interface is defined, you can use:\\n\\n- ${inputs.key} to link with flow input.\\n- ${upstream_node_name.output} to link with single-output upstream node.\\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\\n\\nBelow are common scenarios for linking nodes together.\", \"start_char_idx\": 2, \"end_char_idx\": 313, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.", "document_node": "{\"id_\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c06825b-2eca-437e-81ef-b400683e5107\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dc503dd0dd29d203ef8868753fef7c97754d409dead2aab234f87acf6388f82b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"text\": \"Scenario 1 - Link LLM node with flow input and single-output upstream node\\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \\nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link the LLM node input with flow input by `${inputs.url}`. \\nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \\nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n url: ${inputs.url} # Link with flow input\\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \\nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \\n\\n!link_llm_with_flow_input_single_output_node\\n:::\\n\\n::::\\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \\n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1746, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.", "document_node": "{\"id_\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57a1605b-80c4-4052-8504-33374b92caee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8cf98f614b216b0d506c5cbbb9581ef3ca68bad51e3877c4935b7ef16ecb6e4c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"text\": \"Scenario 2 - Link LLM node with multi-output upstream node\\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \\nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\\n\\n!link_llm_with_multi_output_node\\n:::\\n::::\\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1273, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.", "document_node": "{\"id_\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8126884c-df49-43ba-9d3f-1a9638cd235d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a42c7be5b7c364c1f60b09c4d2756084cd1c9d628ef3fad2380f9b736ce02b20\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"text\": \"Scenario 3 - Link Python node with upstream node/flow input\\nAfter you add a new Python node and edit the code file like Define Python node interface], \\ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \\nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n```yaml\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs:\\n input_str: ${inputs.url} # Link Python node with flow input\\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n!link_python_with_flow_node_input\\n:::\\n\\n::::\\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \\ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1045, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::", "document_node": "{\"id_\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c8228df-9c72-4af5-b9c4-7369ed0f78e8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"35e2f7644a2153debed83c13170ff3cc72a2a0396587f4c47bebb3e814c9c005\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"text\": \"Set flow output\\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \\nmultiple nodes in one place. Moreover, flow output helps:\\n\\n- Check bulk test results in one single table.\\n- Define evaluation interface mapping.\\n- Set deployment response schema.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \\nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \\n`convert_to_dict`.\\n\\n```yaml\\noutputs:\\n category:\\n type: string\\n reference: ${convert_to_dict.output.category}\\n evidence:\\n type: string\\n reference: ${convert_to_dict.output.evidence}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \\nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \\n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\\n\\n!flow_output\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1194, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.", "document_node": "{\"id_\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"66907d7f-5f3f-48c2-9669-2c366a8ae143\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"75e4c5eee350016added3ec9fe497df916fbd71d627b305a3190eb538cc362a4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"text\": \"Referencing external files/folders in a flow\\n\\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\\n\\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/classify_with_llm.jinja2\\n- ../web-classification/convert_to_dict.py\\n- ../web-classification/fetch_text_content_from_url.py\\n- ../web-classification/prepare_examples.py\\n- ../web-classification/summarize_text_content.jinja2\\n- ../web-classification/summarize_text_content__variant_1.jinja2\\n```\\n\\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\\n\\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n```\\n\\nThe entry file \\\"fetch_text_content_from_url.py\\\" of the tool node \\\"fetch_text_content_from_url\\\" is located in \\\"../web-classification/fetch_text_content_from_url.py\\\", as specified in the additional_includes field. The same applies to the \\\"summarize_text_content\\\" tool nodes.\\n\\n> **Note**:\\n>\\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\\nTake the following YAML structure as an example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/prepare_examples.py\\n- ../tmp/prepare_examples.py\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n``` \\n\\nIn this case, the system will use \\\"../tmp/prepare_examples.py\\\" as the entry file for the tool node \\\"prepare_examples\\\". Even if there is a file named \\\"prepare_examples.py\\\" in the flow folder, the system will still use the file \\\"../tmp/prepare_examples.py\\\" specified in the `additional_includes` field.\\n\\n> Tips:\\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.\", \"start_char_idx\": 2, \"end_char_idx\": 3451, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.", "document_node": "{\"id_\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2b7611-b6e8-41d5-bcb7-857e344fb92a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"14430280f768c113dbf9e583b57be7eb327a7edbaf80889e72c017b668b89311\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"text\": \"Adding a tool icon\\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\\n\\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.\", \"start_char_idx\": 2, \"end_char_idx\": 295, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference.", "document_node": "{\"id_\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57058ab8-fa89-4e8a-a86f-8f8f6d8843bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb4c72a52e728f4c06cb906c2535c4d2d1e3e2b9c9ccf274d6c6fa6a2257c4c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"text\": \"Prerequisites\\n\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\\n- Create a tool package as described in Create and Use Tool Package.\\n- Prepare custom icon image that meets these requirements:\\n\\n - Use PNG, JPG or BMP format.\\n - 16x16 pixels to prevent distortion when resizing.\\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \\n\\n See this example as a reference.\", \"start_char_idx\": 2, \"end_char_idx\": 526, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Add tool icon with _icon_ parameter", "document_node": "{\"id_\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5b08ae97-5546-4d8a-8170-1e00ceabc742\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"200723951d139ca9f747a814fe55f43bf4c437d9ca9165060bd9ec9962224d93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"text\": \"Add tool icon with _icon_ parameter\", \"start_char_idx\": 2, \"end_char_idx\": 37, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```", "document_node": "{\"id_\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"04cb4765-6550-47b7-9cee-1ae8b0d9dfef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bfa267daed05b823404227af4ca8eaabad2e04b3069149430390fe220d5df245\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"text\": \"Initialize a package tool with icon\\nYou can use pf tool init to initialize a package tool with icon:\\n```bash\\npf tool init --package --tool --set icon=\\n```\\n\\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\\n```python\\nfrom pathlib import Path\\n\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n icon=Path(__file__).parent.parent / \\\"icons\\\" / \\\"custom-tool-icon.png\\\"\\n)\\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\\n\\nThe folder structure of the generated tool package is as follows:\\n```\\n\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u251c\\u2500\\u2500\\u2500icons\\n\\u2502 \\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500\\n .py\\n utils.py\\n __init__.py\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1222, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension", "document_node": "{\"id_\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a6b4670f-1911-41c2-816e-2afb835bce01\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1abe48bedddbcc1787d670a0952e7a3a82f2de7afce76d2d985ec9d05645a0cd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"text\": \"Verify the tool icon in VS Code extension\\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \\n!custom-tool-with-icon-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 176, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```", "document_node": "{\"id_\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9538f81c-1db6-4c2a-bbb5-ef36ca94fe44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbae9925b9e8426daba0ea2c01d494ed28a0e6dfd7437106812478371a299361\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"text\": \"FAQ\\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\\n```\\npython \\\\tool\\\\convert_image_to_data_url.py --image-path -o \\n```\\nFor example:\\n```\\npython D:\\\\proj\\\\github\\\\promptflow\\\\scripts\\\\tool\\\\convert_image_to_data_url.py --image-path D:\\\\proj\\\\github\\\\promptflow\\\\examples\\\\tools\\\\tool-package-quickstart\\\\my_tool_package\\\\icons\\\\custom-tool-icon.png -o output.html\\n```\\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\\n```html\\n\\n\\n\\n\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 580, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```", "document_node": "{\"id_\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"699ce5b2-187c-46f3-9f9c-b3b535acd91c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d707888b7220646c246f2b7886f82a2e315b193744d4f9c407ffd60a44e1c6a3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"text\": \"Can I add a tool icon to an existing tool package\\n\\nYou can follow these steps to add an icon to an existing package tool:\\n1. Copy the icon image to the package folder.\\n2. Configure the icon for the tool.\\n\\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\\n ```python\\n from promptflow import tool\\n\\n @tool(name=\\\"tool_name\\\", icon=)\\n def tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n ```\\n3. Update `MANIFEST.in` in the package folder.\\n\\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\\n ```\\n include \\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 769, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.", "document_node": "{\"id_\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca4ccdf3-090d-45f9-9d6a-07979afc72ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3d4af681b648feaf107b311553825afe2354879d3aec8e50615a0ed039d2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"text\": \"Can I add tool icons for dark and light mode separately?\\nYes, you can add the tool icon data to the tool code as follows:\\n```python\\nfrom promptflow import tool\\n\\n@tool(name=\\\"tool_name\\\", icon_dark=, icon_light=)\\ndef tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n```\\n\\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\\n```python\\npf tool init --tool --set icon_dark= icon_light=\\n```\\n\\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.\", \"start_char_idx\": 2, \"end_char_idx\": 756, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field.", "document_node": "{\"id_\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01518a9e-e18d-4949-9626-094903eea51c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be5cd30b0f09f966dbb2e5f5edbbbd36d25301c73f444f5f31f9585dba4c0c81\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"text\": \"Adding category and tags for tool\\n\\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\\n\\n| Attribute | Type | Required | Description |\\n| --------- | ---- | -------- | ----------- |\\n| category | str | No | Organizes tools into folders by common features. |\\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\\n\\n**Important Notes:**\\n- Tools without an assigned category will be listed in the root folder.\\n- Tools lacking tags will display an empty tags field.\", \"start_char_idx\": 2, \"end_char_idx\": 1063, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.", "document_node": "{\"id_\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8779355d-d614-4b16-835d-d0721a33dc45\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74313f42ccdbca8b27db5e01299294ae7b0bf1a6ec47b19245225df77fa5f403\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 186, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```", "document_node": "{\"id_\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8d6db4b6-5a82-49d7-ac61-f26dfe211484\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8444fd90e8cf147e712f4a38ad588c732d2520d4f678a8b1455c1853ec50da8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"text\": \"How to add category and tags for a tool\\n\\nYou can use pf tool init to initialize a package tool with category and tags:\\n```python\\npf tool init --package --tool --set category= tags=\\n\\n```\\n\\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\\n```python\\npf tool init --tool my_tool --set name=\\\"My First Tool\\\" description=\\\"This is my first tool\\\" category=\\\"test_tool\\\" tags=\\\"{'tag1':'value1','tag2':'value2'}\\\"\\n```\\nThe generated tool script is as follows, where category and tags have been configured on the tool:\\n```python\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n category=\\\"test_tool\\\",\\n tags={\\\"tag1\\\": \\\"value1\\\", \\\"tag2\\\": \\\"value2\\\"},\\n)\\ndef my_tool(self, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1189, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag", "document_node": "{\"id_\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddf33403-cee1-4e76-a2ab-f6ec20ab5391\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce8dfca466c3c5f8a3b0f25cefa6575a14aac45fc4c6bd71b81025b60a999429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"text\": \"Tool with category and tags experience in VS Code extension\\nFollow the steps to use your tool via the VS Code extension.\\n- Experience in the tool tree\\n!category_and_tags_in_tool_tree\\n\\n- Experience in the tool list\\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\\n!category_and_tags_in_tool_list\\nFurthermore, you have the option to search or filter tools based on tags:\\n!filter_tools_by_tag\", \"start_char_idx\": 2, \"end_char_idx\": 443, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```", "document_node": "{\"id_\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"344346f5-1b0d-44f2-9731-80d27521e130\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4efeae08cd9f495b68b9d5c9738dbcf9caa03eae09cf94a5fc1567bd33f706d5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"text\": \"FAQ\\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\\n```python\\n@tool(\\n name=\\\"tool_name\\\",\\n description=\\\"This is tool_name tool\\\",\\n category=,\\n tags=,\\n)\\ndef tool_name(input_text: str) -> str:\\n # tool logic\\n pass\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 285, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list", "document_node": "{\"id_\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8eb7c175-5eb4-4be1-904f-f815a877641c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"761b3c022375969240ebb1501804424057266c488c43981e362d1b0a23a21831\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"text\": \"Create and use tool package\\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\\n\\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\\n\\nAfter successful installation of the package, your custom \\\"tool\\\" will show up in VSCode extension as below: \\n!custom-tool-list\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.", "document_node": "{\"id_\": \"936062d7-da6f-425e-8071-eec693938da0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4e9a3b-17ed-41b4-af95-541b9285769d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6d0592c1fbf449100098a1897232c851f0023246794d1404df65486e26b30ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"text\": \"Create your own tool package\\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.\", \"start_char_idx\": 2, \"end_char_idx\": 150, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```", "document_node": "{\"id_\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02d44090-c629-4857-8fb8-f857f9743f31\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c283b0aa603e66d9c0593d1f97704896afe43f3c0562e30fdd8b1490164d4b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"text\": \"Prerequisites\\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\\n```\\npip install promptflow\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure.", "document_node": "{\"id_\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cb076bf-bda4-491f-b36b-90646bf39825\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4d88291fa44db81f7df84aa930a343b8e56aa76fbd22cd6831525a828d2bdb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"text\": \"Create custom tool package\\nYou can use pf tool init to initialize a package tool in current folder:\\n\\n```bash\\npf tool init --package --tool \\n\\n```\\nFor example:\\n```bash\\npf tool init --package hello_world --tool hello_world_tool\\n```\\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\\n\\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\\n\\n```\\nhello_world/\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500hello_world/\\n hello_world_tool.py\\n utils.py\\n __init__.py\\n```\\n\\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\\n\\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \\n\\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\\n ```python\\n entry_points={\\n \\\"package_tools\\\": [\\\" = :\\\"],\\n },\\n ```\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\", \"start_char_idx\": 2, \"end_char_idx\": 3024, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.", "document_node": "{\"id_\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb45998c-8b7b-47c6-8563-3cc43e460689\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e56c43e15838921293454392a9f5431b91b0d337bc691b653cef4250b6d5e52b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"text\": \"Build and share the tool package\\n Execute the following command in the tool package root directory to build your tool package:\\n ```\\n python setup.py sdist bdist_wheel\\n ```\\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\\n\\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\\n\\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\\n\\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.\", \"start_char_idx\": 2, \"end_char_idx\": 1081, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension", "document_node": "{\"id_\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a2aac4b6-dee0-40c8-b78f-fa6c85823c0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6dac8b1537a6e23487b63d97bffeeda30df26f43280d740357e8e84c36c3081a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"text\": \"Use your tool from VSCode Extension\\n* Step1: Install Prompt flow for VS Code extension. \\n\\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\\n ```\\n (local_test) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> conda activate prompt-flow\\n (prompt-flow) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> pip install .\\\\dist\\\\my_tools_package-0.0.1-py3-none-any.whl\\n ``` \\n\\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\\n!auto-list-tool-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 745, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.", "document_node": "{\"id_\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25ceaf4b-d75c-452e-b038-cb1cff034017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a67937099d4ff70a170e33ffc30f7d928d2833bfa58a1bbe333e21e7507e09e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"text\": \"FAQs\\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\\n\\n 1. Make sure to install the tool package in your conda environment before executing this script.\\n 2. Create a python file anywhere and copy the content below into it.\\n ```python\\n import importlib\\n import importlib.metadata\\n\\n def test():\\n \\\"\\\"\\\"List all package tools information using the `package-tools` entry point.\\n\\n This function iterates through all entry points registered under the group \\\"package_tools.\\\"\\n For each tool, it imports the associated module to ensure its validity and then prints\\n information about the tool.\\n\\n Note:\\n - Make sure your package is correctly packed to appear in the list.\\n - The module is imported to validate its presence and correctness.\\n\\n Example of tool information printed:\\n ----identifier\\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\\n \\\"\\\"\\\"\\n entry_points = importlib.metadata.entry_points()\\n PACKAGE_TOOLS_ENTRY = \\\"package_tools\\\"\\n if isinstance(entry_points, list):\\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\\n else:\\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\\n for entry_point in entry_points:\\n list_tool_func = entry_point.load()\\n package_tools = list_tool_func()\\n\\n for identifier, tool in package_tools.items():\\n importlib.import_module(tool[\\\"module\\\"]) # Import the module to ensure its validity\\n print(f\\\"----{identifier}\\\\n{tool}\\\")\\n\\n if __name__ == \\\"__main__\\\":\\n test()\\n ```\\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.\", \"start_char_idx\": 2, \"end_char_idx\": 2062, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.", "document_node": "{\"id_\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"361d2447-b4f8-4f35-a1af-8892d249e13a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"55e3663e73f77321999c9beef546505b42179a322bae4b28bb738f35af78f7c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"text\": \"Why am I unable to upload package to PyPI?\\n* Make sure that the entered username and password of your PyPI account are accurate.\\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.\", \"start_char_idx\": 2, \"end_char_idx\": 654, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs", "document_node": "{\"id_\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4c66da-b14f-452c-9927-49b39d9cd181\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8d7ea9fb7c1ff5d72950bbb6b92aa6aafe99722a29b7723c16ec2fae992a4d83\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"text\": \"Advanced features\\n- Add a Tool Icon \\n- Add Category and Tags for Tool \\n- Create and Use Your Own Custom Strong Type Connection \\n- Customize an LLM Tool \\n- Use File Path as Tool Input \\n- Create a Dynamic List Tool Input \\n- Create Cascading Tool Inputs\", \"start_char_idx\": 2, \"end_char_idx\": 258, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.", "document_node": "{\"id_\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f82dbbc6-86b4-4928-8eec-c50b955110f6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbfca4e40603faa2d69519faaf0e6a2bee1c43b0f5f9d625ef9172cf40e2d822\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"text\": \"Creating cascading tool inputs\\n\\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.\", \"start_char_idx\": 2, \"end_char_idx\": 303, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6da446b1-c160-474d-89f3-f9f3659daaa0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f552409c79c5e4003de24d7f1a2f627a4005d8711975f42568830bb585d7fc54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"text\": \"Prerequisites\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 237, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```", "document_node": "{\"id_\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5fbd0902-ccbb-4e1e-b205-f191c87d3f39\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fae50d17a2ec06631c825bbd2772d5c2952857c4632a2670168971f1401afe09\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"text\": \"Create a tool with cascading inputs\\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\\n\\nDevelop the tool function, following the cascading inputs example. Key points:\\n * Use the `@tool` decorator to mark the function as a tool.\\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\\n * Conditionally use inputs in the tool logic based on `user_type`.\\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\\n\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass UserType(str, Enum):\\n STUDENT = \\\"student\\\"\\n TEACHER = \\\"teacher\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Enabled By Value\\\",\\n description=\\\"This is my tool with enabled by value\\\",\\n input_settings={\\n \\\"teacher_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.TEACHER]),\\n \\\"student_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.STUDENT]),\\n }\\n)\\ndef my_tool(user_type: UserType, student_id: str = \\\"\\\", teacher_id: str = \\\"\\\") -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\n :param user_type: user type, student or teacher.\\n :param student_id: student id.\\n :param teacher_id: teacher id.\\n :return: id of the user.\\n If user_type is student, return student_id.\\n If user_type is teacher, return teacher_id.\\n \\\"\\\"\\\"\\n if user_type == UserType.STUDENT:\\n return student_id\\n elif user_type == UserType.TEACHER:\\n return teacher_id\\n else:\\n raise Exception(\\\"Invalid user.\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png", "document_node": "{\"id_\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95ee1c93-3fd8-4ccf-8c4c-76c63f5e6d68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"04fcb935e815a4801293eb7a2cf3895cc849cac7965b173b1c94fff6e473857e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"text\": \"Use the tool in VS Code\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\\n\\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\\n!before_user_type_selected.png\\n!after_user_type_selected_with_student.png\\n!after_user_type_selected_with_teacher.png\", \"start_char_idx\": 2, \"end_char_idx\": 417, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections.", "document_node": "{\"id_\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d27b2b3a-1f85-4708-b438-61936edefd56\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4cc9eeedc959aaa970d6346b761f25e5ade25ff26ab512556114ab76bebacf51\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"text\": \"FAQs\\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass EventType(str, Enum):\\n CORPORATE = \\\"corporate\\\"\\n PRIVATE = \\\"private\\\"\\n\\n\\nclass CorporateTheme(str, Enum):\\n SEMINAR = \\\"seminar\\\"\\n TEAM_BUILDING = \\\"team_building\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Multi-Layer Cascading Inputs\\\",\\n description=\\\"This is my tool with multi-layer cascading inputs\\\",\\n input_settings={\\n \\\"corporate_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[EventType.CORPORATE]),\\n \\\"seminar_location\\\": InputSetting(enabled_by=\\\"corporate_theme\\\", enabled_by_value=[CorporateTheme.SEMINAR]),\\n \\\"private_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[CorporateTheme.PRIVATE]),\\n }\\n)\\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\\"\\\"\\\"\\n pass\\n```\\nInputs will be enabled in a cascading way based on selections.\", \"start_char_idx\": 2, \"end_char_idx\": 1231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.", "document_node": "{\"id_\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67f40a0f-b078-4cc6-ab1e-949e061951a4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"253f1ef689b236779c4139c7b8a8596611a636413e760e9e65f92f24ba76df17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"text\": \"Creating a dynamic list tool input\\n\\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.\", \"start_char_idx\": 2, \"end_char_idx\": 507, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a289ce7d-3868-4476-b3c7-b04b6fffff8f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a62c53dbbe33681ff3ce43af54ec4c0c19328db473d060fb7b1f03598cffe84\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"text\": \"Prerequisites\\n\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 238, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a tool input with dynamic listing", "document_node": "{\"id_\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3cebe967-3b58-4f05-9acc-4b816ed796f9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1936ac053e77c95327c1bc7149e8bce2b7e1f7daf68aacac3294d6b850521487\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"text\": \"Create a tool input with dynamic listing\", \"start_char_idx\": 2, \"end_char_idx\": 42, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```", "document_node": "{\"id_\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e969bbff-b1eb-4490-b321-c72e7e471292\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbf6f556b19f8044dccf35bc5441bc853d43b758c6b30151e64513903af9ff2f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"text\": \"Create a list function\\n\\nTo enable dynamic listing, the tool author defines a request function with the following structure:\\n\\n- Type: Regular Python function, can be in tool file or separate file\\n- Input: Accepts parameters needed to fetch options\\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\\n - Required key:\\n - `value`: Internal option value passed to tool function\\n - Optional keys:\\n - `display_value`: Display text shown in dropdown (defaults to `value`)\\n - `hyperlink`: URL to open when option clicked\\n - `description`: Tooltip text on hover\\n\\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\\n\\n```python\\ndef my_list_func(prefix: str = \\\"\\\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\\n \\\"\\\"\\\"This is a dummy function to generate a list of items.\\n\\n :param prefix: prefix to add to each item.\\n :param size: number of items to generate.\\n :param kwargs: other parameters.\\n :return: a list of items. Each item is a dict with the following keys:\\n - value: for backend use. Required.\\n - display_value: for UI display. Optional.\\n - hyperlink: external link. Optional.\\n - description: information icon tip. Optional.\\n \\\"\\\"\\\"\\n import random\\n\\n words = [\\\"apple\\\", \\\"banana\\\", \\\"cherry\\\", \\\"date\\\", \\\"elderberry\\\", \\\"fig\\\", \\\"grape\\\", \\\"honeydew\\\", \\\"kiwi\\\", \\\"lemon\\\"]\\n result = []\\n for i in range(size):\\n random_word = f\\\"{random.choice(words)}{i}\\\"\\n cur_item = {\\n \\\"value\\\": random_word,\\n \\\"display_value\\\": f\\\"{prefix}_{random_word}\\\",\\n \\\"hyperlink\\\": f'https://www.bing.com/search?q={random_word}',\\n \\\"description\\\": f\\\"this is {i} item\\\",\\n }\\n result.append(cur_item)\\n\\n return result\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2026, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```", "document_node": "{\"id_\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0939118b-828a-4de3-98e9-776c2b8037ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"94f5070b41fbce81858222caf99a4153bd8580851d8f0acf8efaca5417fac9b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"text\": \"Configure a tool input with the list function\\n\\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\\n\\n- `DynamicList`:\\n - `function`: Path to the list function (module_name.function_name).\\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\\n- `is_multi_select`: Allow user to select multiple values. Default to false.\\n\\nSee tool_with_dynamic_list_input.py as an example.\\n\\n```python\\nfrom promptflow._core.tool import tool\\nfrom promptflow.entities import InputSetting, DynamicList\\n\\n\\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\\\"prefix\\\": \\\"input_prefix\\\"})\\ninput_settings = {\\n \\\"input_text\\\": InputSetting(\\n dynamic_list=dynamic_list_setting,\\n allow_manual_entry=True,\\n is_multi_select=True\\n )\\n}\\n\\n\\n@tool(\\n name=\\\"My Tool with Dynamic List Input\\\",\\n description=\\\"This is my tool with dynamic list input\\\",\\n input_settings=input_settings\\n)\\ndef my_tool(input_text: list, input_prefix: str) -> str:\\n return f\\\"Hello {input_prefix} {','.join(input_text)}\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1188, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.", "document_node": "{\"id_\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"241031e5-137a-4f62-8578-f9ae17176b94\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a22fc60300c108cc9ab2a273d80eab0db119f7e244396d4b27e13ac238703bf4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"text\": \"Use the tool in VS Code\\n\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\\n\\n```sh\\npip install my-tools-package>=0.0.8\\n```\\n\\n!dynamic list tool input options\\n!dynamic list tool input selected\\n\\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs", "document_node": "{\"id_\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52cf13ef-f7c7-4777-826e-3436e6fa10a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f155f38296df1d151acb9003db8e8b02ab7afa2138997d07168a8b16c93ecef3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure", "document_node": "{\"id_\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2670701d-65c8-4d71-93bf-9dc1af4ebd73\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e363a58b67cb6b64c1d4d39e722c563b324dcd45713d1ea775f43d875d420f54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"text\": \"I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\\n1. Clarify azure workspace triple \\\"subscription_id\\\", \\\"resource_group_name\\\", \\\"workspace_name\\\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\\n```python\\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \\\"\\\") -> List[Dict[str, str]]:\\n \\\"\\\"\\\"This is an example to show how to get Azure ML resource in tool input list function.\\n\\n :param subscription_id: Azure subscription id.\\n :param resource_group_name: Azure resource group name.\\n :param workspace_name: Azure ML workspace name.\\n :param prefix: prefix to add to each item.\\n \\\"\\\"\\\"\\n from azure.ai.ml import MLClient\\n from azure.identity import DefaultAzureCredential\\n\\n credential = DefaultAzureCredential()\\n credential.get_token(\\\"https://management.azure.com/.default\\\")\\n\\n ml_client = MLClient(\\n credential=credential,\\n subscription_id=subscription_id,\\n resource_group_name=resource_group_name,\\n workspace_name=workspace_name)\\n result = []\\n for ep in ml_client.online_endpoints.list():\\n hyperlink = (\\n f\\\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\\\"\\n f\\\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\\\"\\n f\\\"MachineLearningServices/workspaces/{workspace_name}\\\"\\n )\\n cur_item = {\\n \\\"value\\\": ep.name,\\n \\\"display_value\\\": f\\\"{prefix}_{ep.name}\\\",\\n # external link to jump to the endpoint page.\\n \\\"hyperlink\\\": hyperlink,\\n \\\"description\\\": f\\\"this is endpoint: {ep.name}\\\",\\n }\\n result.append(cur_item)\\n return result\\n```\\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\\n```sh\\naz login\\naz account set --subscription \\naz configure --defaults group= workspace=\\n```\\nInstall azure dependencies.\\n```sh\\npip install azure-ai-ml\\n```\\n```sh\\npip install my-tools-package[azure]>=0.0.8\\n```\\n!dynamic list function azure\", \"start_char_idx\": 2, \"end_char_idx\": 2312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.", "document_node": "{\"id_\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d769cf68-1d72-4689-8a9c-230f570e5cd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0b39012496db8b16e127cf6868f14f256d4316bf3b5682ae7057f2c021b207f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"text\": \"I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\\n\\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\\n\\n\\\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\\\"\\n\\nIf this occurs, follow these troubleshooting steps:\\n\\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.\", \"start_char_idx\": 2, \"end_char_idx\": 627, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.", "document_node": "{\"id_\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5e9e5a08-19ff-47b6-b70e-73ece4cea736\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"058be840749f87c3d4c1a9800979db634ce796b011d542b9d12e4b56f07dca74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"text\": \"Create and use your own custom strong type connection\\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections.", "document_node": "{\"id_\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c9f2fdac-08db-4edb-b3c6-a9088b3a70c8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"709f637c22d9b3f7a184550a7328629e9d8e7db1ca51f15982c8e50964ab1d43\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"text\": \"What is a Custom Strong Type Connection?\\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\\n\\n* Enhanced user experience - no need to manually enter connection keys.\\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\\n* Central location to view available keys and data types.\\n\\nFor other connections types, please refer to Connections.\", \"start_char_idx\": 2, \"end_char_idx\": 534, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fab38a19-7a14-4dbd-bab2-26cfcbc1a9bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cc0011738c8a85337bf926c06c918fa10b64f15184d623d4260ff99b5f86b18a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 230, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation.", "document_node": "{\"id_\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79cde2db-d429-4144-9fef-ecf1150f0b58\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef847fe7289c00e59ef01840ff34bece9995f06b5a69fc566387050ad2b15b33\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"text\": \"Create a custom strong type connection\\nFollow these steps to create a custom strong type connection:\\n\\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\\n\\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\\n\\n3. Document with docstrings explaining each key.\\n\\nFor example:\\n\\n```python\\nfrom promptflow.connections import CustomStrongTypeConnection\\nfrom promptflow.contracts.types import Secret\\n\\n\\nclass MyCustomConnection(CustomStrongTypeConnection):\\n \\\"\\\"\\\"My custom strong type connection.\\n\\n :param api_key: The api key.\\n :type api_key: Secret\\n :param api_base: The api base.\\n :type api_base: String\\n \\\"\\\"\\\"\\n api_key: Secret\\n api_base: str = \\\"This is a fake api base.\\\"\\n\\n```\\n\\nSee this example for a complete implementation.\", \"start_char_idx\": 2, \"end_char_idx\": 883, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:", "document_node": "{\"id_\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7387e95-ab5a-4a70-9c85-229d8acee9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3bbcd908601f7bcffce92d9d792b4b62c388bdf1d0303c84e7b579cf80efc9e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"text\": \"Use the connection in a flow\\nOnce you create a custom strong type connection, here are two ways to use it in your flows:\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow", "document_node": "{\"id_\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a3bd599a-a90a-4cbb-8037-6a13b6dd9c48\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ceaee00a227e4d995d979afa9533af34f51be8bf867a6b10088d37d2a5cca1c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"text\": \"With Package Tools:\\n\\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\\n\\n2. Develop a flow with custom tools. Please take this folder as an example.\\n\\n3. Create a custom strong type connection using one of the following methods:\\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\\n !create_custom_strong_type_connection_in_node_interface\\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\\n !create_custom_strong_type_connection_add_sign\\n - Click 'Create connection' plus sign in the Custom category.\\n !create_custom_strong_type_connection_in_custom_category \\n\\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\\n!custom_strong_type_connection_template\\n\\n5. Run the flow with the created custom strong type connection.\\n!use_custom_strong_type_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 955, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow", "document_node": "{\"id_\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"289b3241-2041-473c-bb43-232c26f7ad82\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b254e2ca79e4eb95b116cabc8863efc8ecc1d1d1e321860eef0efbe3513b0056\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"text\": \"With Script Tools:\\n\\n1. Develop a flow with python script tools. Please take this folder as an example.\\n\\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\\n !custom\\n\\n3. Run the flow with the created custom connection.\\n !use_custom_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```", "document_node": "{\"id_\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9ff5578c-d9c8-4600-8fd2-17be1c3a47bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f490870dcb22fb75d51c9cf96bd148cca6be0f1023c770decb6160254ac5c9a9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"text\": \"Local to cloud\\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\\n\\nPlease refer to Run prompt flow in Azure AI for more details.\\n\\nHere is an example command:\\n```\\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection\\\\data.jsonl --runtime test-compute\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 687, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs", "document_node": "{\"id_\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec0fe169-0696-4b09-a1d4-5378bd80aae4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d1005131a9440a9cbe7be4a33e90326f422b8cce59ff3596ce0213b8cc1def9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.", "document_node": "{\"id_\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"696d6411-2b2e-4bae-88ec-df4715c2cb9c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986a6c2ecd58baffe38dd2942c83b8d33b868ae0a3a4a0a718ebc8c9dca4be53\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"text\": \"I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\\n\\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.\", \"start_char_idx\": 2, \"end_char_idx\": 317, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.", "document_node": "{\"id_\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7fa0f6dc-819e-4c87-8266-b5a9118914d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf6d565ab14197fe3684bddae73d8a73ef4207c61eb95247d99490c74d2d9e7e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"text\": \"Customizing an LLM tool\\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.", "document_node": "{\"id_\": \"60235800-c278-4134-8278-8e27e077672b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6223b1c5-30ec-4887-8019-87b5b08719b0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d4e6526ecfa0dc58bcb2f4ffe54c63f3992a85dd43b94c87bf3443adebc570f7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 103, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```", "document_node": "{\"id_\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6cf8beb9-6705-40b5-b808-781ec0951cc0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6803b97e70221d067b2043774c8b82ade81fdc957a43c72442bb8d905c46b6b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"text\": \"How to customize an LLM tool\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \\n\\nDevelop the tool code as in this example.\\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\\n\\n ```python\\n from jinja2 import Template\\n from promptflow import tool\\n from promptflow.connections import CustomConnection\\n from promptflow.contracts.types import PromptTemplate\\n\\n\\n @tool\\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\\n # Customize your own code to use the connection and prompt here.\\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\\n return rendered_prompt\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 968, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool", "document_node": "{\"id_\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"82bdb8e8-61f7-4a8f-a7f5-11b155607365\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2cf80cfa83e508b387c2eb96683e4e830b00ddaf57323fd26f63ac87e110d0ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"text\": \"Use the tool in VS Code\\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \\n- There is a node named \\\"my_custom_llm_tool\\\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \\n!use_my_custom_llm_tool\", \"start_char_idx\": 2, \"end_char_idx\": 410, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.", "document_node": "{\"id_\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cd195a3-97b4-4a97-82bd-c7d0e87ac685\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"112eaf9f4b6fd25ac3da2887c1935dc9baf039898a60471bebff81abb7c727ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"text\": \"Using file path as tool input\\n\\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\\n\\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 530, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.", "document_node": "{\"id_\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7568039d-4551-48fa-9297-ffb37efc43cf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"59cfa4561fe4293365a4c24a5b539aa6f87ff3607a91d2e043ab8601cec1281a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"text\": \"Prerequisites\\n\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using File Path as Package Tool Input", "document_node": "{\"id_\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"26a93b18-a56a-4cdb-929c-e140981115aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"53b32a0cdc76e7c0bbcc4dc06ef8c4956aa75f189a74a5c1c249410a75f556b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"text\": \"Using File Path as Package Tool Input\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool", "document_node": "{\"id_\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ce61fc15-2cdb-4a63-8987-134e03eb1b6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"281ae66cc1678a8b7eab1188b5b3f2f788aae682ca1ab5226c276b1438877cd8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"text\": \"How to create a package tool with file path input\\n\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\\n\\nAdd a `FilePath` input for your tool, like in this example.\\n\\n```python\\nimport importlib\\nfrom pathlib import Path\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 328, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath", "document_node": "{\"id_\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35d2d03c-9329-41d3-8daf-72bc10887d9b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86d6634bc35fe36a0c204adc8d64ddc65da434342731d413778eb0d1a15923f2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"text\": \"1. import the FilePath type\\nfrom promptflow.contracts.types import FilePath\", \"start_char_idx\": 2, \"end_char_idx\": 77, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.", "document_node": "{\"id_\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"333e8f14-0e51-4937-ba22-d6ecd8476ab9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0d3447a096e1bb3aa918cbd4757bea0a31384731c63c27e170e05d8cd82a188a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"text\": \"2. add a FilePath input for your tool method\\n@tool()\\ndef my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n\\n return new_module.hello(input_text) \\n```\\n\\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.\", \"start_char_idx\": 2, \"end_char_idx\": 427, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow", "document_node": "{\"id_\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7015a1ed-1b19-4e4b-9655-112c9e4e9d22\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"11825ea60a67309ba91e6cb42883fb16318dc1f0f387ff5c3698c09b6e09813f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"text\": \"Use tool with a file path input in VS Code extension\\n\\nFollow steps to build and install your tool package and use your tool from VS Code extension.\\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\\n\\n- There is a node named \\\"Tool_with_FilePath_Input\\\" with a `file_path` type input called `input_file`.\\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\\n\\n !use file path in flow\", \"start_char_idx\": 2, \"end_char_idx\": 487, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool", "document_node": "{\"id_\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd07b5eb-b7cc-42a6-ad08-b9576bd69f78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b1e8f36cab52aa8392c7af80f8578d3cccdb448d4aa2d78149acaa3a2054980c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"text\": \"Using File Path as Script Tool Input\\n\\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\\n\\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\\n ```python\\n import importlib\\n from pathlib import Path\\n from promptflow import tool\\n # 1. import the FilePath type\\n from promptflow.contracts.types import FilePath\\n\\n # 2. add a FilePath input for your tool method\\n @tool\\n def my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n \\n return new_module.hello(input_text) \\n ```\\n\\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\\n \\n !use file path in script tool\", \"start_char_idx\": 2, \"end_char_idx\": 1206, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ", "document_node": "{\"id_\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69991809-43a1-45e0-a7ed-543d5244ca8d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d69baeb0f63d28094f13c861f5b2704b30234f6ee523cbf5dbd3e40438e496a6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"text\": \"FAQ\", \"start_char_idx\": 2, \"end_char_idx\": 5, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.", "document_node": "{\"id_\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"412a990a-7993-48bb-8dae-a040894517aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef4ca3b0ff6e914f8fe374f18dc27d6bcf687fe1838060a4d95ee76c82ba5bb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"text\": \"What are some practical use cases for this feature?\\nThe `FilePath` input enables several useful workflows:\\n\\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\\n\\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.\", \"start_char_idx\": 2, \"end_char_idx\": 605, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.", "document_node": "{\"id_\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb38a3ca-cfe8-4dca-9b10-2466376b3300\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f471b7d48ccb913477b732b2d731cc7b4f592655595022c777f9e92c1ed4808\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"text\": \"Use streaming endpoints deployed from prompt flow\\n\\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\\n\\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\\n\\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\\n\\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.\", \"start_char_idx\": 2, \"end_char_idx\": 835, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png", "document_node": "{\"id_\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"706956f6-48c9-41a9-bb1c-da5a86236d6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3e1a444f441a07ab2df4fd50af04ae49bfb3b215a2bc6535f454b0306e8696e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"text\": \"Create a streaming enabled flow\\n\\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\\n\\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\\n ```jinja\\n {# Sample prompt template for LLM node #}\\n\\n system:\\n You are a helpful assistant.\\n\\n user:\\n {{question}}\\n ```\\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\\n ```python\\n from promptflow import tool\\n\\n # Sample code echo input by yield in Python tool node\\n\\n @tool\\n def my_python_tool(paragraph: str) -> str:\\n yield \\\"Echo: \\\"\\n for word in paragraph.split():\\n yield word + \\\" \\\"\\n ```\\n\\nIn this guide, we will use the \\\"Chat with Wikipedia\\\" sample flow as an example. This flow processes the user\\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\\n\\n!chat_wikipedia.png\", \"start_char_idx\": 2, \"end_char_idx\": 1372, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page.", "document_node": "{\"id_\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6c888e5e-8cc3-40a3-957c-c9490fb07aa7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf83dc0a7e113999480393c58b334373aff1e4fe2bdbed0ff974e231287e4ce7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"text\": \"Deploy the flow as an online endpoint\\n\\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\\n\\nFollow this guide to deploy your flow as an online endpoint.\\n\\n> [!NOTE]\\n> \\n> You can follow this document to deploy an online endpoint.\\n> Please deploy with runtime environment version later than version `20230816.v10`.\\n> You can check your runtime version and update runtime in the run time detail page.\", \"start_char_idx\": 2, \"end_char_idx\": 513, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:", "document_node": "{\"id_\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98c6ee2b-c91e-450b-964c-eb2654ba13bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0034781020f8eb762eb657bec70cf919844120f8791674e17ff9ec21750f2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"text\": \"Understand the streaming process\\n\\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\\n\\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\\n\\nTo understand the streaming process, consider the following steps:\\n\\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \\\"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\\\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\\n > [!NOTE]\\n > \\n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\\n \\n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\\n - If the `Accept` header specifies other media types, such as `text/html`:\\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\\n > Note: Please refer handle errors for details.\\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\\n\\nLet\\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\\n\\nThe overall process works as follows:\", \"start_char_idx\": 2, \"end_char_idx\": 2788, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response.", "document_node": "{\"id_\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddaf9efd-9ac9-4829-a54c-1648089d8d70\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"680ad8077e320e6e398a84f918cd7befe171f7bb12e18aee8904d3e2647b006f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"text\": \"0. The client sends a message to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Hello\\\",\\n \\\"chat_history\\\": []\\n}\\n```\\n> [!NOTE]\\n> \\n> The `Accept` header is set to `text/event-stream` to request a stream response.\", \"start_char_idx\": 2, \"end_char_idx\": 326, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.", "document_node": "{\"id_\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"821fdf27-98c6-43a4-8a2f-c784651596bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3aabc69a0ec2b4ab4cf0c35722875bb5c3a8751390b1eeafc540cc6ab9fd19d8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"text\": \"1. The server sends back the response in streaming mode.\\n\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Hello\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" How\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" assist\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" today\\\"}\\n\\ndata: {\\\"answer\\\": \\\" ?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\\n\\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\\n\\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\\n\\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.\", \"start_char_idx\": 2, \"end_char_idx\": 944, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"912d0e1f-a746-471c-a2a4-71fc2730e575\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d85b5ace9efc60427c9f464f9645bb0589929e638b563f9b7da4c5a5db69026\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Glad to know you!\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"Hello\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"answer\\\": \\\"Hello! How can I assist you today?\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 491, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```", "document_node": "{\"id_\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48347717-5e52-4331-8d92-6a7c54fe3d03\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554b3afb5397fc0a38ddb0164a88ae48a2e944d9d06f047d66f849aed83187aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Nice\\\"}\\n\\ndata: {\\\"answer\\\": \\\" to\\\"}\\n\\ndata: {\\\"answer\\\": \\\" know\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" too\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" there\\\"}\\n\\ndata: {\\\"answer\\\": \\\" anything\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" help\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" with\\\"}\\n\\ndata: {\\\"answer\\\": \\\"?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 607, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "4. The chat continues in a similar way.", "document_node": "{\"id_\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ac508813-a33c-4c2c-a3d1-773e79aef114\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6a748b536cb6dbb48de3c2fc76dfaee7b3ac7bb7e92983c1f6a60a2789577178\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"text\": \"4. The chat continues in a similar way.\", \"start_char_idx\": 2, \"end_char_idx\": 41, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user.", "document_node": "{\"id_\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3fd257bf-5cf8-4f99-bffc-e3bbc6f78390\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56eac9e90da9529ab6e04074e76b19d92a2b351f7e19b21d8973f970dc189c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"text\": \"Handle errors\\n\\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\\n\\nIf the response code is \\\"424 Model Error\\\", it means that the error is caused by the model\\u2019s code. The error response from a PromptFlow model always follows this format:\\n\\n```json\\n{\\n \\\"error\\\": {\\n \\\"code\\\": \\\"UserError\\\",\\n \\\"message\\\": \\\"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\\\",\\n }\\n}\\n```\\n* It is always a JSON dictionary with only one key \\\"error\\\" defined.\\n* The value for \\\"error\\\" is a dictionary, containing \\\"code\\\", \\\"message\\\".\\n* \\\"code\\\" defines the error category. Currently, it may be \\\"UserError\\\" for bad user inputs and \\\"SystemError\\\" for errors inside the service.\\n* \\\"message\\\" is a description of the error. It can be displayed to the end user.\", \"start_char_idx\": 2, \"end_char_idx\": 851, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to consume the server-sent events", "document_node": "{\"id_\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a6fd14f-f375-4da2-a24b-0cafcf1fddf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efe8860eada88de2417ef06be8a0990d2deea819d95cba2e97b9ca1a432e4c54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"text\": \"How to consume the server-sent events\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```", "document_node": "{\"id_\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dd27869b-15cf-42ca-b7e6-50aa08ba0d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7591010f02260b9174a1b2251dc262f58eb1a52ae423e651964800b13059af4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"text\": \"Consume using Python\\n\\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\\n\\n```bash\\npip install sseclient-py \\n```\\n\\nA sample usage would like:\\n\\n```python\\nimport requests \\nfrom sseclient import SSEClient \\nfrom requests.exceptions import HTTPError \\n\\ntry:\\n response = requests.post(url, json=body, headers=headers, stream=stream)\\n response.raise_for_status()\\n\\n content_type = response.headers.get('Content-Type')\\n if \\\"text/event-stream\\\" in content_type:\\n client = SSEClient(response)\\n for event in client.events():\\n # Handle event, i.e. print to stdout\\n else:\\n # Handle json response\\n\\nexcept HTTPError:\\n # Handle exceptions\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 792, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.", "document_node": "{\"id_\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"42e4799e-96c2-4780-a62c-923dc6c72ced\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ee102f88249caf546d0c0bdafd13b8f1a212f9d0775fc8151940e1fee75512c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"text\": \"Consume using JavaScript\\n\\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app", "document_node": "{\"id_\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c8f1f5f-4639-4ce0-a7e3-73399238b474\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3f1b447e5173f4bafc67db22b703f07422d77028dcf992b0553bd73fcd33c9b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"text\": \"A sample chat app using Python\\n\\nHere is a sample chat app written in Python.\\n(Click here to view the source code.)\\n\\n!chat_app\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.", "document_node": "{\"id_\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da359dbe-b196-465f-a58b-923cfa17400e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d36f27b1e6799c33c3a5f8115b7c7535edcea14977513849b56331f899eed90f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"text\": \"Advance usage - hybrid stream and non-stream flow output\\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \\u201cChat with Wikipedia\\u201d flow, you may want to get not only LLM\\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\\u2019s answer and non-stream URL list.\\n\\nIn the sample \\\"Chat With Wikipedia\\\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\\n\\n!chat_wikipedia_dual_output_center.png\\n\\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.\", \"start_char_idx\": 2, \"end_char_idx\": 805, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```", "document_node": "{\"id_\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"14f0a5dd-312e-4539-b900-5b291142a148\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ed2ed3f2b32332867a54f69c94b86e84eeedfce3c36e9a8010183b04b170e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"text\": \"0. The client sends a message to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\",\\n \\\"chat_history\\\": []\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d9f464-762e-4146-9352-9a808af3fde8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"02a6bf0f2539cc26435514fe55f4f59572376600cce1efc190c79b9fcd743123\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"text\": \"1. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\", \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 747, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"016b2ee8-acf4-4bdc-94c7-79463ab4a7db\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0aa2e2ac63ba13015313fe66dfbb8ec4203540014741ea1281303ddb606424c7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When did OpenAI announce GPT-4? How long is it between these two milestones?\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"url\\\": [\\n \\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\",\\n \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"\\n ],\\n \\\"answer\\\": \\\"ChatGPT was launched on November 30, 2022. \\\\n\\\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 833, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9fe0c1e9-3ca5-4c67-9d7c-bb987940b686\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29379ee510ab86ed5cf7ccd99fa4be6d0d1580d210182a61323bbbd0a9a44089\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \\\", \\\"https://en.wikipedia.org/w/index.php?search=Microsoft \\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Open\\\"}\\n\\ndata: {\\\"answer\\\": \\\"AI\\\"}\\n\\ndata: {\\\"answer\\\": \\\" released\\\"}\\n\\ndata: {\\\"answer\\\": \\\" G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"-\\\"}\\n\\ndata: {\\\"answer\\\": \\\"4\\\"}\\n\\ndata: {\\\"answer\\\": \\\" in\\\"}\\n\\ndata: {\\\"answer\\\": \\\" March\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" The\\\"}\\n\\ndata: {\\\"answer\\\": \\\" time\\\"}\\n\\ndata: {\\\"answer\\\": \\\" between\\\"}\\n\\ndata: {\\\"answer\\\": \\\" these\\\"}\\n\\ndata: {\\\"answer\\\": \\\" two\\\"}\\n\\ndata: {\\\"answer\\\": \\\" milestones\\\"}\\n\\ndata: {\\\"answer\\\": \\\" is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" approximately\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\" months\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1458, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::", "document_node": "{\"id_\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e02f01b8-6709-4920-9a8b-7e2c5e77be44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4fa90920b48a86b6763c89f59b0bddae5ecf0338d4fd85cb546c4cddc5864ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"text\": \"Execute flow as a function\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.", "document_node": "{\"id_\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ea36d385-1925-46e4-a5b7-e77f0f3cc6ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f1f3fd175e8d9c564036921a8f4759cac8cbcb556a37d3504935f460547b059\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"text\": \"Overview\\n\\nPromptflow allows you to load a flow and use it as a function in your code.\\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```", "document_node": "{\"id_\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fb1e5741-98bd-4b28-88dd-9c503d0421ef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f813adeab56a408bcb78b566016ee117476fd8356ae2dafe911f856ec3ca07ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"text\": \"Load an invoke the flow function\\n\\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\\nThen you can consume the flow object like a function by providing key-value arguments for it.\\n\\n```python\\nf = load_flow(\\\"../../examples/flows/standard/web-classification/\\\")\\nf(url=\\\"sample_url\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 330, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.", "document_node": "{\"id_\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"91e9d667-cfbc-4f4e-9240-09036f81dfc7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bce2f8b33b0e9c233454a16cc5975de252451fb6c45f3ad82274458c869fa0aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"text\": \"Config the flow with context\\n\\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)", "document_node": "{\"id_\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24e752d6-0029-4218-94ca-93a1465077b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d7195051357847107c3e1134dd358ec6063a42599855d090ebf34cb8707d0774\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"text\": \"Load flow as a function with in-memory connection override\\n\\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\\n\\n```python\\nfrom promptflow.entities import AzureOpenAIConnection\\n\\nconnection_obj = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=api_key,\\n api_base=api_base,\\n api_type=\\\"azure\\\",\\n api_version=api_version,\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```", "document_node": "{\"id_\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dde478bf-d6cb-43a8-b1a4-8d8d35f25e0f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ed8c2e142e9b716c24dadc03b5b75782fb42f44c8ed62da6f2131b6c418f2eb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"text\": \"no need to create the connection object.\\nf.context = FlowContext(\\n connections={\\\"classify_with_llm\\\": {\\\"connection\\\": connection_obj}}\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.", "document_node": "{\"id_\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a9785096-c148-4ec8-9a62-f6b9f80ef601\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1fcfc555a6a8a8a1950f5352afbdd252f325d853dbef81815bb12d212a5afe8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"text\": \"Local flow as a function with flow inputs override\\n\\nBy providing overrides, the original flow dag will be updated in execution time.\\n\\n```python\\nf.context = FlowContext(\\n # node \\\"fetch_text_content_from_url\\\" will take inputs from the following command instead of from flow input\\n overrides={\\\"nodes.fetch_text_content_from_url.inputs.url\\\": sample_url},\\n)\\n```\\n\\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.\", \"start_char_idx\": 2, \"end_char_idx\": 565, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\"", "document_node": "{\"id_\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6b681357-4cac-4553-b6a5-9df520eb030b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac1d912138d7d912b5c51e55b4e77d89d14ff84ee46ca9d1ee92acd7d9898b59\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"text\": \"Load flow as a function with streaming output\\n\\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\\n\\n```python\\nf = load_flow(source=\\\"../../examples/flows/chat/basic-chat/\\\")\\nf.context.streaming = True\\nresult = f(\\n chat_history=[\\n {\\n \\\"inputs\\\": {\\\"chat_input\\\": \\\"Hi\\\"},\\n \\\"outputs\\\": {\\\"chat_output\\\": \\\"Hello! How can I assist you today?\\\"},\\n }\\n ],\\n question=\\\"How are you?\\\",\\n)\\n\\n\\nanswer = \\\"\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage.", "document_node": "{\"id_\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bbbd143-9995-4367-939e-0c831eb263fe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2cfa7009b4997d3fde306b94dbf03de21819f05a14d0aaca580fc15eb62a26d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"text\": \"the result will be a generator, iterate it to get the result\\nfor r in result[\\\"answer\\\"]:\\n answer += r\\n\\n```\\n\\nReference our sample for usage.\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow", "document_node": "{\"id_\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07fb8988-8ef2-4450-aa41-2d21c42ff60a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a44b5c7aad060be11eb17db2bce6368d458f1e720941d3c50c807c071a6ce513\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"text\": \"Next steps\\n\\nLearn more about:\\n\\n- Flow as a function sample\\n- Deploy a flow\", \"start_char_idx\": 2, \"end_char_idx\": 76, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Frequency asked questions (FAQ)", "document_node": "{\"id_\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cb9f4a0f-e680-47fc-8f5d-5b223d51d083\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"743917481836b00908b09ff34a3d165a53a55bbd846807af36b7bb80a22a628c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"text\": \"Frequency asked questions (FAQ)\", \"start_char_idx\": 2, \"end_char_idx\": 33, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "General", "document_node": "{\"id_\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c597cc0b-d110-4165-8c96-53d36acef69d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"814d7155ef3529ff69b2385fcb080cd2c7b7fccacefb5d13c76ea02c151e3825\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"text\": \"General\", \"start_char_idx\": 2, \"end_char_idx\": 9, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.", "document_node": "{\"id_\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0fe4dd5d-e4c5-40ed-98e7-a044021dbf86\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1c42f40448725a9a0bd02a07496b82437c4fbad22447c717ff5a6f9ac9b220e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"text\": \"Stable vs experimental\\n\\nPrompt flow provides both stable and experimental features in the same SDK.\\n\\n|Feature status | Description | \\n|----------------|----------------|\\nStable features\\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.\", \"start_char_idx\": 2, \"end_char_idx\": 1143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details.", "document_node": "{\"id_\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bb3c750-f12d-4808-ab89-acf161dfd91e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6beadd06f30b207f672c997719c336539e7faf8ef36feaf44e40f65c1b4fa868\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"text\": \"OpenAI 1.x support\\nPlease use the following command to upgrade promptflow for openai 1.x support:\\n```\\npip install promptflow>=1.1.0\\npip install promptflow-tools>=1.0.0\\n```\\nNote that the command above will upgrade your openai package a version later than 1.0.0, \\nwhich may introduce breaking changes to custom tool code.\\n\\nReach OpenAI migration guide for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 369, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Troubleshooting", "document_node": "{\"id_\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e9acc577-1cbb-429e-970d-7c98723202ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af390d4c747d81b170f3d982c0a82884e61001ce8fe19ffbddc01b21b7d24626\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"text\": \"Troubleshooting\", \"start_char_idx\": 2, \"end_char_idx\": 17, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.", "document_node": "{\"id_\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6ba934f9-e5d6-4550-8a2f-0c6be54cd508\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8e9e6602be667f9cba044453ac50a9f815cf9662bbf038f534f5481bbbc3305b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"text\": \"Connection creation failed with StoreConnectionEncryptionKeyError\\n\\n```\\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\\n```\\n\\nThis error raised due to keyring can't find an available backend to store keys.\\nFor example macOS Keychain and Windows Credential Locker\\nare valid keyring backends.\\n\\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\\n`pip install keyrings.alt`\\n\\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.\", \"start_char_idx\": 2, \"end_char_idx\": 773, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.", "document_node": "{\"id_\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7499f3d-3746-45d8-bddc-7b8e7726100f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fb9686bc123c832e95558b925d4fb46cc4c621ce1ad04658d3092dc3e77c89\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"text\": \"Pf visualize show error: \\\"tcgetpgrp failed: Not a tty\\\"\\n\\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\\n\\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.\", \"start_char_idx\": 2, \"end_char_idx\": 367, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.", "document_node": "{\"id_\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0a6a1158-c713-4412-b59d-b85f18e89f0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"67bd1cc4115725959bb26b2e210e9bc34bdafb0f300364d873e67e7b6d1a203c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"text\": \"Installed tool not appearing in VSCode Extension tool list\\n\\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\\n\\n!VSCode Extension tool list\\n\\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\\n\\n1. Open the VSCode Extension window.\\n\\n2. Bring up the command palette by pressing \\\"Ctrl+Shift+P\\\".\\n\\n3. Type and select the \\\"Developer: Reload Webviews\\\" command. \\n\\n4. Wait a moment for the tool list refreshing.\\n\\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.\", \"start_char_idx\": 2, \"end_char_idx\": 716, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img", "document_node": "{\"id_\": \"98caef46-1716-47c8-8950-80296635edb6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8b886825-981c-4d7a-a456-b29e07a0f2c3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6b854d9357a3adff77eaf7bdce41cc3375c66d93c1da46c6f7928d8fc0c13fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"text\": \"Set logging level\\n\\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\\n\\n!img\\n\\nCompare to the serving logs with `WARNING` level:\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.", "document_node": "{\"id_\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"576f95f6-92d9-483f-822a-0ce9bf0bd395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45f83f4fb0b797a2d06fb8a2f9cfeb3c6c9008f2be62d661550b4b1311b1934a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"text\": \"Set environment variables\\n\\nCurrently, promptflow supports the following environment variables:\\n\\n**PF_WORKER_COUNT** \\n\\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\\n\\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\\n\\nWhen you modify the concurrency, please consider 2 points:\\n\\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\\n\\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\\n\\n```\\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\\n```\\nTPM: token per minute, capacity rate limit of your LLM endpoint\\n\\nduration_seconds: single flow run duration in seconds\\n\\ntoken_count: single flow run token count\\n\\n\\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\\n\\n**PF_BATCH_METHOD**\\n\\nValid for batch run only. Optional values: 'spawn', 'fork'. \\n\\n**spawn**\\n\\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\\n\\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\\n \\n**fork**\\n\\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\\n\\n2. The process starts faster as it doesn't need to reinitialize resources.\\n \\nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.\", \"start_char_idx\": 2, \"end_char_idx\": 2366, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```", "document_node": "{\"id_\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1bb38f65-df51-4e35-9339-b39205a74d42\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5ffb3a0055a7127117140f63d34e4ee966af213db99b4fa728c673465b4004c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"text\": \"You can configure environment variables in the following ways\\n\\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\\\"2\\\" PF_BATCH_METHOD=\\\"spawn\\\"```.\\n\\n2. If you are using SDK, you can specify environment variables when creating run. Example: \\n\\n``` python\\n pf = PFClient(\\n credential=credential,\\n subscription_id=\\\"\\\",\\n resource_group_name=\\\"\\\",\\n workspace_name=\\\"\\\",\\n )\\n\\n flow = \\\"web-classification\\\"\\n data = \\\"web-classification/data.jsonl\\\"\\n runtime = \\\"example-runtime-ci\\\"\\n\\n environment_variables = {\\\"PF_WORKER_COUNT\\\": \\\"2\\\", \\\"PF_BATCH_METHOD\\\": \\\"spawn\\\"}\\n\\n # create run\\n base_run = pf.run(\\n flow=flow,\\n data=data,\\n runtime=runtime,\\n environment_variables=environment_variables,\\n )\\n```\\n\\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\\n\\n``` yaml\\n name: flow_name\\n display_name: display_name\\n flow: flow_folder\\n data: data_file\\n column_mapping:\\n customer_info: \\n history: \\n environment_variables:\\n PF_WORKER_COUNT: \\\"2\\\"\\n PF_BATCH_METHOD: \\\"spawn\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1240, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it.", "document_node": "{\"id_\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2d12cb4e-9982-46b1-8020-5a397a5c70ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27490f9ccc0a4ef12bcef73484eb8f041e969282c05eff50bb23a31b4394ca93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"text\": \"Initialize and test a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, customer can initialize a flow and test it.\", \"start_char_idx\": 2, \"end_char_idx\": 208, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow.", "document_node": "{\"id_\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"223ae55b-31d0-4a3f-a845-e2cbb48d2174\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a987c0ab8aa00ab20a17431c70079e376558edd598e742211a1b6d6323108503\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"text\": \"Initialize flow\\n\\nCreating a flow folder with code/prompts and yaml definitions of the flow.\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a5ad4e4-84f4-4725-8096-3096c1ce097f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9d2f6bed32465c8afd0d71f4ff8109ac9daee9f05c58a3b9afe2016bca66aa5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"text\": \"Initialize flow from scratch\\n\\nPromptflow can create three types of flow folder:\\n- standard: Basic structure of flow folder.\\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 525, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a flow\npf flow init --flow", "document_node": "{\"id_\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a66b4440-7ab7-4a0a-8e3e-cf53ce0da183\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c55a21ae37e2c8abc954550c17e8d4ae89c001cbd51afbdf6250026ab8111cd7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"text\": \"Create a flow\\npf flow init --flow\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder", "document_node": "{\"id_\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3979a8ce-fe87-4ab5-b144-4b734aa35c25\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"184c77063135f92e2154daff06d061bfd4a0dc94f3d65875b712e2986daca02a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"text\": \"Create a chat flow\\npf flow init --flow --type chat\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse VS Code explorer pane > directory icon > right click > the \\\"New flow in this directory\\\" action. Follow the popped out dialog to initialize your flow in the target folder.\\n!img\\n\\nAlternatively, you can use the \\\"Create new flow\\\" action on the prompt flow pane > quick access section to create a new flow\\n!img\\n\\n:::\\n\\n::::\\n\\n\\nStructure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n!init_flow_folder\", \"start_char_idx\": 2, \"end_char_idx\": 847, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash", "document_node": "{\"id_\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15bc22d5-c272-430d-b04a-79cfe65f18fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"66785e16e82b7ffa50adb19068670cd130f8b3dc6ab081a908061308b313ce3c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"text\": \"Create from existing code\\n\\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 414, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files", "document_node": "{\"id_\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8a15b7b7-5711-4d86-917f-4fc2036c6027\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6c03c3df69e37b72e57a0a75ca81f10041bf1c7f5b9b1a3c8506b13f6aa43f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"text\": \"Create a flow in existing folder\\npf flow init --flow --entry --function --prompt-template =\\n```\\n\\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\\n\\n!init_output\\n\\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\\n\\n!init_files\", \"start_char_idx\": 2, \"end_char_idx\": 396, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.", "document_node": "{\"id_\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95cd3374-d155-4f86-b29d-fb4bf987e22b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9422effd2aaeb2748e289c5baf349916d999564c3179e620610f11eb42dd375e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"text\": \"Test a flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::", "document_node": "{\"id_\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2aafc740-6302-4dbf-a42d-ee1dea0c6ebf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"446896168b129cd5539cb3091ff4073483ad34e324321c181d6a0901e0abd70a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"text\": \"Visual editor on the VS Code for prompt flow.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \\\"Visual editor\\\" action. Use it to open the Visual editor with GUI support.\\n\\n!img\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 300, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ee0cc84-3f98-42e6-8a67-fbdee3586ccc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b83ff835b3a805eb03482d718707c0e686d12752df5f55dce13fd7e2fcaf50a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"text\": \"Test flow\\n\\nCustomer can use CLI or VS Code extension to test the flow.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\npf flow test --flow", "document_node": "{\"id_\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd5cefe7-28c9-4bf0-9fc6-8b3609de5b5a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"229f3f16a238a91b31c7e47ac2e91406ec163f09cd791edd3eb594209a03c0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"text\": \"Test flow\\npf flow test --flow\", \"start_char_idx\": 2, \"end_char_idx\": 31, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"49dd7bd1-552d-40a9-8f03-e533f0e08d54\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ddf2f5446188a40b24a32a024a1b0544334ba529ecba86dda4f49f1d4be2129\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"text\": \"Test flow with specified variant\\npf flow test --flow --variant '${.}'\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 577, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d1ad1393-927d-41d6-8139-7e599f0f06e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"89b24a887590553199b9ee0c1b9fc51a85ab692e6db323dbdcd22c2255e9a892\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 702, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash", "document_node": "{\"id_\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4eb28b8-dc68-48de-87fe-746453fa405a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"125b62feb2a0b81e72c1bbb54a25128fe0ef760e2cf21a4de506ac04bc14cc5e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"text\": \"Test a single node in the flow\\n\\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nCustomer can execute this command to test the flow.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 337, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7b80b991-92a3-41ea-a747-36708cbc9dd2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68553f1861f970ef898e05440d384d9c431f59f1b74bb863b93bba6b233fac22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"text\": \"Test flow node\\npf flow test --flow --node \\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 419, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"18f1adbf-ecc3-4b53-8418-89329a15ce5e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd07e53bbd4061d9ac9e11b6f588c17761eb7b3a19c7444a286fc89370fc0325\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"text\": \"Test not iun the flow\\ninputs = {: } # The inputs of the node.\\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 533, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash", "document_node": "{\"id_\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd754830-349c-4e11-a781-bb24512461e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3d66f9f55eb3364c049a109ae76e0f366d5b39f746f9732b4cc63961d184d1b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"text\": \"Test with interactive mode\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 234, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1dfba4cb-27ff-46d4-9f89-6e585c66e7af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"15964bbe99b83f7830453b5a2e5113f3bef996cda9aa8ef777a98643873a429f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"text\": \"Chat in the flow\\npf flow test --flow --interactive\\n```\\n\\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\\n\\nUsing this chat flow to show how to use interactive mode.\\n\\n!chat\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\\n\\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe flow result will be streamed in the terminal as shown below.\\n\\n!streaming_output\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 1162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::", "document_node": "{\"id_\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf5960ff-bb2a-46e1-91ec-56aca552ecbd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c8c2606c9b6fb9f5472c28e53817c83a807118199ca561ac221ee50d994050db\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nfor item in flow_result[\\\"\\\"]:\\n print(item)\\n```\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 169, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bdc16d88-1916-4304-a6f7-440c9efca1ca\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82e4d3ca19496b8c5d4386adfd56d7eaa8cc032e8c7c141ef4c7e886eef46caa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"text\": \"Debug a single node in the flow\\n\\nCustomer can debug a single python node in VScode by the extension.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 374, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\n- Add conditional control to a flow", "document_node": "{\"id_\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d5caefb5-8563-48c6-814b-b513309e144c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86f72212dd70181df51676601190b6b412486d8aeeaeca9885371345ea964535\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"text\": \"Next steps\\n\\n- Add conditional control to a flow\", \"start_char_idx\": 2, \"end_char_idx\": 49, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::", "document_node": "{\"id_\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c679040-3627-4e7a-8599-ae144332c763\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bc0144e32aa85d7452b6071e6e0ac610d0995a2640ead996bc906162475a7c77\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"text\": \"Manage connections\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\\n\\n:::{note}\\nTo use azureml workspace connection locally, refer to this guide.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 422, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.", "document_node": "{\"id_\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c4ff6b8-fe67-4ec7-9eea-a84769ed42fa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9fc840fdb46639dfa7f2c0c5525c7397a8b717192d4e4fd05796d2a5443e72d7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"text\": \"Connection types\\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\\n\\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 502, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash", "document_node": "{\"id_\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48897b0d-44af-4c0a-8411-f4048af44ce9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"849f9eedece63c894efdd476e9e1bb3dde2e5c55044c6a782b51bf3bb4b48b7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"text\": \"Create a connection\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: azure_open_ai_connection\\ntype: azure_open_ai\\napi_key: \\\"\\\"\\napi_base: \\\"https://.openai.azure.com/\\\"\\napi_type: \\\"azure\\\"\\napi_version: \\\"2023-03-15-preview\\\"\\n```\\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\\nname: custom_connection\\ntype: custom\\nconfigs:\\n endpoint: \\\"\\\"\\n other_config: \\\"other_value\\\"\\nsecrets: # required\\n my_key: \\\"\\\"\\n```\\nAfter preparing the yaml file, use the CLI command below to create them:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1078, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key=", "document_node": "{\"id_\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"87222c5e-4f77-4b93-8d69-d5f7af5f06f3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0e4402c636bd9dd666a5652039e3f48b4f98339d223f75428020f237415d64fa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"text\": \"Override keys with --set to avoid yaml file changes\\npf connection create -f --set api_key=\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection", "document_node": "{\"id_\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"415192cd-10f2-45df-b939-9de5ea5c8ee0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d9fac2f2493f493188f30ca653a58bf91bee6219703e2123ffaafdb01a378519\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"text\": \"Create the custom connection\\npf connection create -f --set configs.endpoint= secrets.my_key=\\n```\\nThe expected result is as follows if the connection created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5ac1b34a-f365-46b2-af27-98df27795edb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d704aa2ec218d1b1acc8c01252d81cd49440df151dd5ec4a92ccf0fbb54a87ff\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)", "document_node": "{\"id_\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddfa8c7c-cdd4-4073-ad8c-34534a20b49a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a7db8e137fd4c7c07d1f4ae406b7ee0b2aad89be313957c12e3d2c9efdf5538\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"text\": \"Initialize an AzureOpenAIConnection object\\nconnection = AzureOpenAIConnection(\\n name=\\\"my_azure_open_ai_connection\\\", \\n api_key=\\\"\\\", \\n api_base=\\\"\\\"\\n api_version=\\\"2023-03-15-preview\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 193, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)", "document_node": "{\"id_\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86e2c793-3cb8-4ec7-bc7d-44576f1a8170\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0a0e5bcab0cc6aca9da6836e7fd11cd9442b42270019b48113f33540fb9d8d40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"text\": \"Create the connection, note that api_key will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)", "document_node": "{\"id_\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a130569c-c523-4a83-be04-b4706f124c1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"011cb400a1083e76cc32cc921b1a71a76b18dde3df75f4b224a9b9e1d9434f90\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"text\": \"Initialize a custom connection object\\nconnection = CustomConnection(\\n name=\\\"my_custom_connection\\\", \\n # Secrets is a required field for custom connection\\n secrets={\\\"my_key\\\": \\\"\\\"},\\n configs={\\\"endpoint\\\": \\\"\\\", \\\"other_config\\\": \\\"other_value\\\"}\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e783be9d-0148-44a5-ab4f-dd0523ac8334\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"751dfc933b0e96e74f8ce306a449da30d196af0146bd2bf18261f765194c180f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"text\": \"Create the connection, note that all secret values will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \\\"+\\\" icon on the top right of it and follow the popped out instructions to create your new connection.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 463, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash", "document_node": "{\"id_\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e85cc25f-3348-406f-af8a-2754d2339ac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ff8b3d46333114d6aa64b7572fc631715461e38af0f2ddf90f5bd6ceefe0483\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"text\": \"Update a connection\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe commands below show how to update existing connections with new values:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'", "document_node": "{\"id_\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3abffd3b-ed39-4218-bce7-5becbd65db6c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74e7f2cb5f8df53cffe2b8bf20c9755b3e0cd188ab67d8f242d74e36cd2d5773\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"text\": \"Update an azure open ai connection with a new api base\\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python", "document_node": "{\"id_\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"50207311-5c91-4251-a254-720a7b40926a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"73a939ef359ad24d3ddae75e1280b2e91a6cca8a37caa45b3b798800a099da3a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"text\": \"Update a custom connection\\npf connection update -n my_custom_connection --set configs.other_config='new_value'\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nThe code snippet below shows how to update existing connections with new values:\\n```python\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)", "document_node": "{\"id_\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c76ef7e2-4457-4746-aa80-44d36f3e679d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e529352592a59587b997627812a31f186d8aad0960591837b21f31fcca158ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"text\": \"Update an azure open ai connection with a new api base\\nconnection = pf.connections.get(name=\\\"my_azure_open_ai_connection\\\")\\nconnection.api_base = \\\"new_value\\\"\\nconnection.api_key = \\\"\\\" # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\", \"start_char_idx\": 2, \"end_char_idx\": 312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"63dd3856-a79f-497b-a8e0-aa61b446d692\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5025c879a00830a327e4ec3f23a86b5566cb9fa543823d37bbe40e4c5cec352\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"text\": \"Update a custom connection\\nconnection = pf.connections.get(name=\\\"my_custom_connection\\\")\\nconnection.configs[\\\"other_config\\\"] = \\\"new_value\\\"\\nconnection.secrets = {\\\"key1\\\": \\\"val1\\\"} # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f6d9da7-52eb-4abf-8a2e-a927ee735541\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d3ea86a42100eb1fe366be6811c4eeaac9dfb41944fb89ba80ff1b66f248a615\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"text\": \"List connections\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\\n```bash\\npf connection list\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 415, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f51d9a42-127f-4ea9-9792-e149e8a38a7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02057374-00f7-431d-9da0-156db1202852\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5700cd94662430caae88bb657f1bca9ea785a2616bc964557182744191e247dc\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"text\": \"List and print connections\\nconnection_list = pf.connections.list()\\nfor connection in connection_list:\\n print(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 191, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9829818d-2389-4b7a-b824-87ff80e4e5bc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50527ec74e94bfc190f0dbf98b325f1f2e187c5ac5ec86d7a09dfee41c9592c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"text\": \"Delete a connection\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nDelete a connection with the following command:\\n```bash\\npf connection delete -n \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nDelete a connection with the following code snippet:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 279, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e31a56f7-dfde-4662-a545-e3382f5d2395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"09e1d45a-e995-4845-9819-61a50a7e3fcc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62a9b42d19dc3a2618a57b3123475f3e48b57c65cef1d43fd9918153ffb040ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"text\": \"Delete the connection with specific name\\nclient.connections.delete(name=\\\"my_custom_connection\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI.", "document_node": "{\"id_\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"345ef80f-a13b-4a7a-a85c-fcb140faf879\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d5386667d921191043732d28b80d2062181886d4c8ab54880eaed2e9a80f6a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"text\": \"Next steps\\n- Reach more detail about connection concepts.\\n- Try the connection samples.\\n- Consume connections from Azure AI.\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run", "document_node": "{\"id_\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb5ce587-ed3b-4933-90a2-cd69af33569a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f5704af61f5056221d2e79bc09b64b5866186f2a9d92c1973198f7ad601ff0c2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"text\": \"Manage runs\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \\n\\nIn general:\\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\\n\\nLet's take a look at the following topics:\\n\\n- Manage runs\\n - Create a run\\n - Get a run\\n - Show run details\\n - Show run metrics\\n - Visualize a run\\n - List runs\\n - Update a run\\n - Archive a run\\n - Restore a run\", \"start_char_idx\": 2, \"end_char_idx\": 668, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash", "document_node": "{\"id_\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2f925fe9-ce2c-4854-b77b-13180f4a0960\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2128e989c9a49e28690407060252f2ed66ab45c3e599f65cfcd28e80fa2cdde9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"text\": \"Create a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nTo create a run against bulk inputs, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../web_classification\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n url: \\\"${data.url}\\\"\\nvariant: ${summarize_text_content.variant_0}\\n```\\n\\nTo create a run against existing run, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../classification_accuracy_evaluation\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n groundtruth: \\\"${data.answer}\\\"\\n prediction: \\\"${run.outputs.category}\\\"\\nrun: \\n```\\n\\nReference here for detailed information for column mapping.\\nYou can find additional information about flow yaml schema in Run YAML Schema.\\n\\nAfter preparing the yaml file, use the CLI command below to create them:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 940, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create the flow run\npf run create -f", "document_node": "{\"id_\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e8f49d4b-09cb-4725-b400-3e6a57e6f756\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1f5b6613de87d844d48e200c9b9c9059eeec4f91a3db91eecb7cdab65d19814c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"text\": \"create the flow run\\npf run create -f\", \"start_char_idx\": 2, \"end_char_idx\": 38, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run", "document_node": "{\"id_\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69b30e6f-ae04-4662-b070-0d2f621ebefe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4633642239f0ea5e8c401ec55305ae8b31da7edc8a8b8d683eb99d6fe9106406\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"text\": \"create the flow run and stream output\\npf run create -f --stream\\n```\\n\\nThe expected result is as follows if the run is created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import Run\", \"start_char_idx\": 2, \"end_char_idx\": 409, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7d2a225f-8af5-476f-89c9-80c92eeb0470\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad254fb5c3bfa9051eb14e7387114c2a5c1c76bbb931108fe180d2bb19b7054\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)", "document_node": "{\"id_\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd6f0ea0-d59d-4713-9cd0-ba3eb0e65942\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48b09a6ad917a748e77953d709c4a0363847b171256aca5776de986d2a3403cf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"text\": \"Initialize an Run object\\nrun = Run( \\n flow=\\\"\\\",\\n # run flow against local data or existing run, only one of data & run can be specified. \\n data=\\\"\\\",\\n run=\\\"\\\",\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n variant=\\\"${summarize_text_content.variant_0}\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 264, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d537c095-e0b4-4578-bd01-a7a6ecfdaa26\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbdad1ed5255e045338bc1ee9997c8440345b0219f5f7c566599525647199619\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"text\": \"Create the run\\nresult = pf.runs.create_or_update(run)\\nprint(result)\\n\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 301, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aa7fb66b-5547-4381-8445-5b889fbd750d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"670696330b3c61d1dd01ad6a0443001a2420bde7594a46160f3014ae731abb72\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"text\": \"Get a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet a run in CLI with JSON format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 233, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f49dcc8e-cb73-4d39-9315-4850fbf8574f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fd00d1e-3ff5-4e22-b9f3-6b9035a840f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b3bab73b36683da5ccd33b89ba1de7fe035ca591a43a5a2a2343c5ff007be74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"text\": \"Get and print the run\\nrun = pf.runs.get(name=\\\"\\\")\\nprint(run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate", "document_node": "{\"id_\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"056517ad-77d6-4567-bd42-784249e7099e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac8e842a7b5768c58167cad9416d5c3a46f31c4ca4b60615181298880853c1d0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"text\": \"Show run details\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run details with TABLE format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run details with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nfrom tabulate import tabulate\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9528494c-6fe6-435e-8311-638da383dc41\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f68960fd-78ed-4eb5-9c21-41c88a20f97c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"49293e272e5907c1688626b39b858b564c40e0a463d3bbf18bc4ae7e5851ac17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"text\": \"Get and print the run-details\\nrun_details = pf.runs.get_details(name=\\\"\\\")\\nprint(tabulate(details.head(max_results), headers=\\\"keys\\\", tablefmt=\\\"grid\\\"))\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 216, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json", "document_node": "{\"id_\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bafa7c22-c619-45f8-9c0d-e8fca3753d61\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cf1e0bec2347094aba059e8ccaea3ab4d987ec96d413c8f38bc4c038be5a274\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"text\": \"Show run metrics\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run show-metrics --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run metrics with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nimport json\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f36b0ba6-a935-419f-be60-64b86bfcd0af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::", "document_node": "{\"id_\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0acc4e77-5cef-41d4-8dd5-2d3ee287789a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305909b84d1072067287befc0fbbab8cd1a5653d9336a909d32a9bacc21cf2d3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"text\": \"Get and print the run-metrics\\nrun_details = pf.runs.get_metrics(name=\\\"\\\")\\nprint(json.dumps(metrics, indent=4))\\n```\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f1c9b212-965b-41d9-808f-a859cf2bcf64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f7b2bd2c6d767e2394c033cf46a8b2756409e7a2158e17b96e651c5c5ff13ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"text\": \"Visualize a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nVisualize run in browser.\\n\\n```bash\\npf run visualize --name \\n```\\n\\nA browser will open and display run outputs.\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nVisualize run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 286, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"83ebe531-d05f-4a18-b981-b032188e1a91\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::", "document_node": "{\"id_\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d47b6b-d1bb-4135-99c6-94e0587982d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2dd6d3b52ab30d4dda87b658da7a20d31661a20e90afadbfd6ba9ee96ada3ab0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"text\": \"Visualize the run\\nclient.runs.visualize(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \\\"visualize\\\" button on the top-right to visualize the local runs.\\n\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 341, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8cd0973b-621c-4ac5-ab7b-b761e9464968\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b8464057578b5ba3ccb4ef18e6269f22e0645221ea15c48138dba649196cbf3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"text\": \"List runs\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nList runs with JSON format.\\n\\n```bash\\npf run list\\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 215, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"689f1a61-021c-4d09-8f36-af664354d82a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::", "document_node": "{\"id_\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"62d58288-30a7-403a-ae78-e96ab797625a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8658b0ec41f3abc61402be75b54a6e1ae936ba8728c5ca85595757a37f92b1c8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"text\": \"list runs\\nruns = pf.runs.list()\\nprint(runs)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a882a5b2-ae70-4e60-8dec-44ab6aa5de17\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a99bfa43094dbfe48415d7cfa311835783debea8e004b3617c06d72e8a9f14e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"text\": \"Update a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run update --name --set display_name=new_display_name\\n```\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUpdate run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 269, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d622f6da-925e-4499-b2bc-e6c1b88a7764\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::", "document_node": "{\"id_\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"12a0c48d-32ba-458c-b98b-5ce685fbecd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f180fb15fb20882c0f33f6f5bcf0d9c267d70b9f7fd04436d7be890c0ae9fbb1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"text\": \"Get and print the run-metrics\\nrun = pf.runs.update(name=\\\"\\\", display_name=\\\"new_display_name\\\")\\nprint(run)\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 118, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0e1f5935-4d6c-42a3-9b09-3da53cf5dbc6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a226c721d83c0dc240f7149e90068679e1185971e0efc5cd3750d3688f7be6f4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"text\": \"Archive a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nArchive the run so it won't show in run list results.\\n\\n```bash\\npf run archive --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nArchive with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 251, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a01b3d2-3028-4464-8113-24d35a37127c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67df2602-4039-4fc6-b097-7d52f3ab80d3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3105c8e1a55b304a67ffac4d9723179527619bd43eb7fb30ba9e8be0057b447\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"text\": \"archive a run\\nclient.runs.archive(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 110, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"73b1be5c-105b-4991-a760-2cdc603ef913\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3515081b130b61184610302211a976ed86236d28529ea29de4e4062eeed2b6fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"text\": \"Restore a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nRestore an archived run so it can show in run list results.\\n\\n```bash\\npf run restore --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nRestore with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 257, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a6b2dca-a015-4f46-8e4c-8f420c172cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::", "document_node": "{\"id_\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52013f35-f7b9-4ead-99a3-ce4a40a7b0a0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9ff0a8fc8da582672ffd435dede081836c045e4c0bfad1bc35f00dd9ddd90b1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"text\": \"restore a run\\nclient.runs.restore(name=\\\"\\\")\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data.", "document_node": "{\"id_\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3f073cc8-dbd7-404a-b000-72bbff9558a2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b0fe45f7655286420820fe760ab00a37e2f5838b36fb118fc4ec5008b5f86060\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"text\": \"Process image in flow\\nPromptFlow defines a contract to represent image data.\", \"start_char_idx\": 2, \"end_char_idx\": 78, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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.", "document_node": "{\"id_\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5efdffd0-715a-49b8-b862-8c06fd69756a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9037551182ef68ff8573f23d59d51ab0122c07bd8b67195a7927188e9cdfc942\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"text\": \"Data class\\n`promptflow.contracts.multimedia.Image`\\nImage 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.\", \"start_char_idx\": 2, \"end_char_idx\": 338, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image.", "document_node": "{\"id_\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"be5c5590-cc2c-471d-9a1a-9d6ba6654b4a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9cfbe119c907229fa7c21d195971a302e523c3d4fd165529faabcbe96bc04923\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"text\": \"Data type in flow input\\nSet the type of flow input to `image` and promptflow will treat it as an image.\", \"start_char_idx\": 2, \"end_char_idx\": 105, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.", "document_node": "{\"id_\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbc9ce4b-d4c9-4821-9508-f9923f82ce76\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae851217d3af4fca9c7ef102cf46a9c6e94d378388c1ce5ec771632962af0989\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"text\": \"Reference image in prompt template\\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario.", "document_node": "{\"id_\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25990bbe-88b7-404e-b27b-dba038a55cab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c110c9ce51caed1fd070c097b462340c73e276069cb4bf96a739d73cba30a06e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"text\": \"Serialization/Deserialization\\nPromptflow uses a special dict to represent image.\\n`{\\\"data:image/;\\\": \\\"\\\"}`\\n\\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\\n- `` is the image serialized representation, there are 3 supported types:\\n\\n - url\\n\\n It can point to a public accessable web url. E.g.\\n\\n {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\\\"}\\n - base64\\n\\n It can be the base64 encoding of the image. E.g.\\n\\n {\\\"data:image/png;base64\\\": \\\"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\\\"}\\n\\n - path\\n\\n 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.\\n\\n {\\\"data:image/png;path\\\": \\\"./my-image.png\\\"}\\n\\nPlease note that `path` representation is not supported in Deployment scenario.\", \"start_char_idx\": 2, \"end_char_idx\": 1496, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```", "document_node": "{\"id_\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19d77c76-c58e-4192-90d8-c49cb217b41c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92124ab99bd3cf499149ae86dd3f01b6d954639f457778cad90613e5049ac45e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"text\": \"Batch Input data\\nBatch input data containing image can be of 2 formats:\\n1. 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.\\n ```json\\n {\\\"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\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/404.png\\\"}}\\n ```\\n2. 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:\\n ```\\n BatchInputFolder\\n |----input.jsonl\\n |----image1.png\\n |----image2.png\\n ```\\n Content of `input.jsonl`\\n ```json\\n {\\\"question\\\": \\\"How many colors are there in the image?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image1.png\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image2.png\\\"}}\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1318, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.", "document_node": "{\"id_\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13b2e87c-864e-48d7-a298-aa0405987f0e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"79570951aa402f8b5f4e3c3b8c54c819fcb929b1a4d6de04a5f0a9e9b9d305c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"text\": \"Quick Start\\n\\nThis guide will walk you through the fist step using of prompt flow code-first experience.\\n\\n**Prerequisite** - To make the most of this tutorial, you'll need:\\n\\n- Know how to program with Python :)\\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\\n\\n\\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\\n- Setup your python environment to run prompt flow\\n- Clone a sample flow & understand what's a flow\\n- Understand how to edit the flow using visual editor or yaml\\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.\", \"start_char_idx\": 2, \"end_char_idx\": 623, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash", "document_node": "{\"id_\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cccf3a8-00b2-4eea-925d-a6d165906fb2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"587ff0eab41d0c313506a1b48bba59f016d271767a7706df438d3b94b95d70f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"text\": \"Set up your dev environment\\n\\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\\n```bash\\nconda create --name pf python=3.9\\nconda activate pf\\n```\\n\\n2. Install `promptflow` and `promptflow-tools`.\\n```sh\\npip install promptflow promptflow-tools\\n```\\n\\n3. Check the installation.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 457, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```", "document_node": "{\"id_\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"38042954-c5f8-49e2-ad7a-8dd102cb9e4b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c85e37e9cb465346ff4d30d688adc584079228796b48af10d2c71ceb2335616\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"text\": \"should print promptflow version, e.g. \\\"0.1.0b3\\\"\\npf -v\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 59, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.", "document_node": "{\"id_\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2ba34ea4-ae4b-4056-b39f-5912c5a0fa64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a4f168922683539a819e5ea2cd78f563c61381d82a343207632856d7d161254\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"text\": \"Understand what's a flow\\n\\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```", "document_node": "{\"id_\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a05adf23-8e8c-45aa-b2af-53428b3c4ab3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb849308243c212f582c607ade0182cb365a92c8d404b5e5fb594118d2c07357\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"text\": \"Get the flow sample\\n\\nClone the sample repo and check flows in folder examples/flows.\\n\\n```bash\\ngit clone https://github.com/microsoft/promptflow.git\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79a0a064-1fcf-426a-8548-0cbbbe034e7c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44b92b2fd3a018be8e3053359e32a4423d9b6474f12db760ac37fe43281bbb32\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"text\": \"Understand flow directory\\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\\n\\n```bash\\ncd promptflow/examples/flows/standard/web-classification\\n```\\n\\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n\\n!flow_dir\\n\\nIn order to run this specific flow, you need to install its requirements first.\\n\\n```sh\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 946, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section.", "document_node": "{\"id_\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e7c432c7-346e-4c79-9d66-4944eaab2398\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"585f3bbe83645c654d93216d5a9b001b56b9ef008cf9693379ade54887ec1a42\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"text\": \"Understand the flow yaml\\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\\n\\n!flow_dag\\n\\nThis graph is rendered by VS Code extension which will be introduced in the next section.\", \"start_char_idx\": 2, \"end_char_idx\": 274, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode", "document_node": "{\"id_\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5d15c1f0-b882-4e0f-a58e-b1f1e5f9e228\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81e60ad7a846d99edaec0186774aa9ebb0110cb857c56d2328868b7e0fa46711\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"text\": \"Using VS Code Extension to visualize the flow\\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\\n\\n1. Prerequisites for VS Code extension.\\n - Install latest stable version of VS Code\\n - Install VS Code Python extension\\n\\n2. Install Prompt flow for VS Code extension\\n\\n3. Select python interpreter\\n\\n !vscode\\n !vscode\\n\\n\\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\\n !vscode\", \"start_char_idx\": 2, \"end_char_idx\": 497, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop and test your flow", "document_node": "{\"id_\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"720071dc-66cc-4ed4-9b59-173a870d30ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"714af737aa81a554f0df7e22fd1b79dcdd62a3fbdd515c290cad89305d189339\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"text\": \"Develop and test your flow\", \"start_char_idx\": 2, \"end_char_idx\": 28, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow.", "document_node": "{\"id_\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"488319e9-bfcd-4afc-a6dc-d9dc568d8222\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4280e9afda0f6e201ad8aa74bea5818f07bfee49457a332e90c7775a5b169aea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"text\": \"How to edit the flow\\n\\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\\ninputs:\\n url:\\n type: string\\n # change the default value of input url here\\n default: https://play.google.com/store/apps/details?id=com.twitter.android\\n...\\n```\\nSee more details of this topic in Develop a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 532, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection", "document_node": "{\"id_\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aba5bfb1-05ae-468c-be62-0a1a07c9d628\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4304344b05c441a6eb462f8c791c8d9a04408b2ff3ebeb03674bafdc081a41e3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"text\": \"Create necessary connections\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n\\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\\n\\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\\n\\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nFirstly we need a connection yaml file `connection.yaml`:\\n\\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: azure_open_ai\\napi_key: \\napi_base: \\napi_type: azure\\napi_version: \\n```\\n\\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: open_ai\\napi_key: \\\"\\\"\\norganization: \\\"\\\" # optional\\n```\\nThen we can use CLI command to create the connection.\\n\\n```sh\\npf connection create -f connection.yaml\\n```\\n\\nMore command details can be found in CLI reference.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nIn SDK, connections can be created and managed with `PFClient`.\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection\", \"start_char_idx\": 2, \"end_char_idx\": 1802, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections.", "document_node": "{\"id_\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c529519b-67a4-4ca2-82d6-88e7699c8200\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ed7487a25062f53a7b930269186ea7f0954012d2027cad99b2715db455927b9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"text\": \"PFClient can help manage your runs and connections.\\npf = PFClient()\\n\\ntry:\\n conn_name = \\\"open_ai_connection\\\"\\n conn = pf.connections.get(name=conn_name)\\n print(\\\"using existing connection\\\")\\nexcept:\\n connection = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=\\\"\\\",\\n api_base=\\\"\\\",\\n api_type=\\\"azure\\\",\\n api_version=\\\"\\\",\\n )\\n\\n # use this if you have an existing OpenAI account\\n # from promptflow.entities import OpenAIConnection\\n # connection = OpenAIConnection(\\n # name=conn_name,\\n # api_key=\\\"\\\",\\n # )\\n\\n conn = pf.connections.create_or_update(connection)\\n print(\\\"successfully created connection\\\")\\n\\nprint(conn)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n\\n\\n1. Click the promptflow icon to enter promptflow control panel\\n\\n !vsc_add_connection\\n\\n2. Create your connection.\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n\\n:::\\n\\n::::\\n\\nLearn more on more actions like delete connection in: Manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 1030, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name", "document_node": "{\"id_\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6e2090d9-29f8-4fce-90c8-b577f114642b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d5a26e33893b1d820d9201b77c301375b1bac6e1020962824c2eab192622768\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"text\": \"Test the flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\n\\nAssuming you are in working directory `promptflow/examples/flows/standard/`\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nChange the default input to the value you want to test.\\n\\n!q_0\\n\\n```sh\\npf flow test --flow web-classification # \\\"web-classification\\\" is the directory name\\n```\\n\\n!flow-test-output-cli\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow/node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient()\\n\\nflow_path = \\\"web-classification\\\" # \\\"web-classification\\\" is the directory name\", \"start_char_idx\": 2, \"end_char_idx\": 793, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")", "document_node": "{\"id_\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00d12aa2-2fba-4094-ba89-2b5100553cbf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2eb38f79e9511a30a686a54c0c9328d8f27b6533f88da23af285578f841f825c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"text\": \"Test flow\\nflow_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\", \\\"answer\\\": \\\"Channel\\\", \\\"evidence\\\": \\\"Url\\\"} # The inputs of the flow.\\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\", \"start_char_idx\": 2, \"end_char_idx\": 243, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow.", "document_node": "{\"id_\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c8481bc3-2fa6-4f9e-bbcf-50426bc810c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2f184b383bba7eaa575f03d802ddda93cb93c77c0c9aa1a1b18fc95da8c0b85c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"text\": \"Test node in the flow\\nnode_name = \\\"fetch_text_content_from_url\\\" # The node name in the flow.\\nnode_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\"} # The inputs of the node.\\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\n!Flow test outputs\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse the code lens action on the top of the yaml editor to trigger flow test\\n!dag_yaml_flow_test\\n\\n\\nClick the run flow button on the top of the visual editor to trigger flow test.\\n!visual_editor_flow_test\\n:::\\n\\n::::\\n\\nSee more details of this topic in Initialize and test a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 666, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.", "document_node": "{\"id_\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cd6ec34-2ff3-4ef6-a334-5325a792d6be\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f922b16e03e9c87176794882ed1ecdce02c8480f87787e537137efa790a4d7b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"text\": \"Next steps\\n\\nLearn more on how to:\\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\\n- Deploy a flow: how to deploy the flow as a web app.\\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\\n\\nAnd you can also check our examples, especially:\\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.\", \"start_char_idx\": 2, \"end_char_idx\": 1011, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow.", "document_node": "{\"id_\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"30c31860-92f8-47c4-8143-ed8a60bef754\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6456b9cffe36ddc31ab56d1934541df995350acf57169caef45954e5432ef45\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"text\": \"Use column mapping\\n\\nIn this document, we will introduce how to map inputs with column mapping when running a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 116, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column.", "document_node": "{\"id_\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f7f2a950-7877-4434-9ad9-91c026212720\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7463dd8b40dd4febe72041037b50febcc30e9f037aa9038b0930a4ce8aed2b8a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"text\": \"Column mapping introduction\\n\\nColumn mapping is a mapping from flow input name to specified values.\\nIf specified, the flow will be executed with provided value for specified inputs.\\nThe following types of values in column mapping are supported:\\n\\n- `${data.}` to reference from your test dataset.\\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\\n- `STATIC_VALUE` to create static value for all lines for specified column.\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow", "document_node": "{\"id_\": \"54218434-a846-4601-b725-da39ad450bac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3b22908e-2696-4ca0-ab38-15c436581212\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a65e49af872870820c0aa44888d4bec1d26b74f685c8f8f6b0e82e567dcaa2e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"text\": \"Flow inputs override priority\\n\\nFlow input values are overridden according to the following priority:\\n\\n\\\"specified in column mapping\\\" > \\\"default value\\\" > \\\"same name column in provided data\\\".\\n\\nFor example, if we have a flow with following inputs:\\n\\n```yaml\\ninputs:\\n input1:\\n type: string\\n default: \\\"default_val1\\\"\\n input2:\\n type: string\\n default: \\\"default_val2\\\"\\n input3:\\n type: string\\n input4:\\n type: string\\n...\\n```\\n\\nAnd the flow will return each inputs in outputs.\\n\\nWith the following data\\n\\n```json\\n{\\\"input3\\\": \\\"val3_in_data\\\", \\\"input4\\\": \\\"val4_in_data\\\"}\\n```\\n\\nAnd use the following YAML to run\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: path/to/flow\", \"start_char_idx\": 2, \"end_char_idx\": 718, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data", "document_node": "{\"id_\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85ecd312-c7aa-48ca-89cb-4d16ac411b2d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"924fbc0961d3d7d9de76a32f571c6ff05573670311e7c52c2288ea2aa20c43da\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"text\": \"my_flow has default value val2 for key2\\ndata: path/to/data\", \"start_char_idx\": 2, \"end_char_idx\": 60, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data.", "document_node": "{\"id_\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e74459fb-15d7-4a3d-ae93-101437c2bd75\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"698d6a2dc2865dae75ed798ff334ae53e59410e15e656c44e2cedc8fd117bb6b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"text\": \"my_data has column key3 with value val3\\ncolumn_mapping:\\n input1: \\\"val1_in_column_mapping\\\"\\n input3: ${data.input3}\\n```\\n\\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\\n\\n!column_mapping_details\\n\\n- Input \\\"input1\\\" has value \\\"val1_in_column_mapping\\\" since it's specified as constance in `column_mapping`.\\n- Input \\\"input2\\\" has value \\\"default_val2\\\" since it used default value in flow dag.\\n- Input \\\"input3\\\" has value \\\"val3_in_data\\\" since it's specified as data reference in `column_mapping`.\\n- Input \\\"input4\\\" has value \\\"val4_in_data\\\" since it has same name column in provided data.\", \"start_char_idx\": 2, \"end_char_idx\": 657, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.", "document_node": "{\"id_\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0745af7e-ec63-49a3-8913-9ce62b2de223\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27e034e72d909f547920ecb5bfea736f1ab1e439d826daa7d913ef75116ce89f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"text\": \"Set global configs\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\\n\\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.\", \"start_char_idx\": 2, \"end_char_idx\": 541, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```", "document_node": "{\"id_\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c304b195-516b-47e0-900a-fbad4496fde3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"88f72ac96bfaa0b271618b9c8f66bcc2de5d37e2a9e6d26e26bcc54921321ebd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"text\": \"Set config\\n```shell\\npf config set =\\n```\\nFor example:\\n```shell\\npf config set connection.provider=\\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 200, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```", "document_node": "{\"id_\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a73d8903-c78a-4ef8-8591-c5fe90893d80\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"264d76e266c35e6a139d87b304d20aaf5393fe43b13ece323df3ff74b235e613\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"text\": \"Show config\\nThe following command will get all configs and show them as json format:\\n```shell\\npf config show\\n```\\nAfter running the above config set command, show command will return the following result:\\n```json\\n{\\n \\\"connection\\\": {\\n \\\"provider\\\": \\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n }\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 358, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values.", "document_node": "{\"id_\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b56e2759-71a4-4872-aac3-59ee3a94a1f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1761fcf18f56ea37a32fff9d05bc05935c4d26f821644ab355085b65b7d1a304\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"text\": \"Supported configs\\nThe connection provider, default to \\\"local\\\". There are 3 possible provider values.\", \"start_char_idx\": 2, \"end_char_idx\": 102, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.", "document_node": "{\"id_\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e66b553-7359-4b97-afdc-8f38395dc946\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09bfdea661db0c1bc689c1372efa2a0820d2f05cbcaebd5f56fb3e0542f42848\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"text\": \"local\\nSet connection provider to local with `connection.provider=local`.\\n\\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.\", \"start_char_idx\": 2, \"end_char_idx\": 252, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::", "document_node": "{\"id_\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07f8fe3d-7333-4508-a442-6d98e99eef0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"91bd5a95942ac400dca084af0a6320249f0b2e643d08b786e6608b413a891d7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"text\": \"full azure machine learning workspace resource id\\nSet connection provider to a specific workspace with:\\n```\\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\n```\\n\\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\\n\\n:::{note}\\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 701, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.", "document_node": "{\"id_\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ca93927-7b13-4533-a448-2c9898d0a1c7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d2ac101a7dad86028f9b2b6cc6cb864cf7a91da7f23df582bc7a081651a09b19\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"text\": \"azureml\\nIn addition to the full resource id, you can designate the connection provider as \\\"azureml\\\" with `connection.provider=azureml`. In this case,\\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\\n\\nThe expected format of the config file is as follows:\\n```json\\n{\\n \\\"workspace_name\\\": \\\"\\\",\\n \\\"resource_group\\\": \\\"\\\",\\n \\\"subscription_id\\\": \\\"\\\"\\n}\\n\\n```\\n\\n> \\ud83d\\udca1 Tips\\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.\", \"start_char_idx\": 2, \"end_char_idx\": 763, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first.", "document_node": "{\"id_\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f4b19098-b649-49fb-ba3a-256c50177102\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f1d3fdba7aff41e34517c387405f43a643cc9bdc273d4608b5b84dabc5b8561e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"text\": \"Tune prompts using variants\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nTo better understand this part, please read Quick start and Run and evaluate a flow first.\", \"start_char_idx\": 2, \"end_char_idx\": 236, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence.", "document_node": "{\"id_\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"596d09b8-71b6-4d61-8033-f700c9e6e166\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f86c56fcebb73fc409192845f5a32aeb1bdc75a71e12db269ab09c95f37353ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"text\": \"What is variant and why should we care\\n\\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\\u2019s accuracy, diversity, or coherence.\", \"start_char_idx\": 2, \"end_char_idx\": 400, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\"", "document_node": "{\"id_\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"042639b8-edf6-4943-b574-68f37cb821e5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3891ba9e1032a54312c877719e8bc6185815a78c2077ee309de42674e31602f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"text\": \"Create a run with different variant node\\n\\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\\n\\n\\n```yaml\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n...\\nnode_variants:\\n summarize_text_content:\\n default_variant_id: variant_0\\n variants:\\n variant_0:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '128'\\n temperature: '0.2'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n variant_1:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content__variant_1.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '256'\\n temperature: '0.3'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n```\\n\\nYou can check the whole flow definition in flow.dag.yaml.\\n\\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \\nAssuming you are in working directory `/examples/flows/standard`\\n\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote we pass `--variant` to specify which variant of the node should be running.\\n\\n```sh\\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\\n```\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient() # get a promptflow client\\nflow = \\\"web-classification\\\"\\ndata= \\\"web-classification/data.jsonl\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 2080, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.", "document_node": "{\"id_\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8551fee8-9698-4a4e-a6c2-68ad0c5ad168\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4b1feb415aba95a00177594f96a7c35009b9cc3a06174dfdc0557050e30fdb0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"text\": \"use the variant1 of the summarize_text_content node.\\nvariant_run = pf.run(\\n flow=flow,\\n data=data,\\n variant=\\\"${summarize_text_content.variant_1}\\\", # use variant 1.\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n)\\n\\npf.stream(variant_run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n!img\\n!img\\n:::\\n\\n::::\\n\\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.\", \"start_char_idx\": 2, \"end_char_idx\": 465, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI", "document_node": "{\"id_\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98e9445a-c154-4bc3-9647-d54e3459349d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2fbfc42e24e9a1378f4fafdbd1334335ff983a743a84920e31777f80cf4f2921\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"text\": \"Next steps\\n\\nLearn more about:\\n- Run and evaluate a flow\\n- Deploy a flow\\n- Prompt flow in Azure AI\", \"start_char_idx\": 2, \"end_char_idx\": 99, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/src/test_data_gen_local/config.ini b/examples/test_data_gen/src/test_data_gen_local/config.ini deleted file mode 100644 index 83629622b1c..00000000000 --- a/examples/test_data_gen/src/test_data_gen_local/config.ini +++ /dev/null @@ -1,11 +0,0 @@ -; should_skip_doc_split = True -documents_folder = "D:\proj\github\ms\promptflow\docs\how-to-guides" -document_chunk_size = 1024 -; cspell: ignore luyao -document_nodes_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" -; test data gen flow configs -flow_folder = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow" -flow_batch_run_size = 10 -connection_name = "azure_open_ai_connection" -; test data output path -test_data_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\test_data" diff --git a/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py deleted file mode 100644 index d9f72af02fc..00000000000 --- a/examples/test_data_gen/src/test_data_gen_local/run_test_data_gen.py +++ /dev/null @@ -1,110 +0,0 @@ -import os -from datetime import datetime - -import configargparse - -from promptflow import PFClient -from promptflow.entities import Run - -UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "src", "utils")) -if UTILS_PATH not in os.sys.path: - os.sys.path.insert(0, UTILS_PATH) - -from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE # noqa: E402 -from common import split_document, clean_data_and_save # noqa: E402 - -CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) - - -def batch_run_flow( - pf: PFClient, - flow_folder: str, - flow_input_data: str, - flow_batch_run_size: int, - connection_name: str = "azure_open_ai_connection", -): - print("#### Start to submit the batch run.") - base_run = pf.run( - flow=flow_folder, - data=flow_input_data, - stream=True, - environment_variables={ - "PF_WORKER_COUNT": str(flow_batch_run_size), - "PF_BATCH_METHOD": "spawn", - }, - connections={key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items()}, - column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, - debug=True, - ) - - print("#### Batch run is completed.") - - return base_run - - -def get_batch_run_output(pf: PFClient, base_run: Run): - print(f"#### Start to get batch run {base_run.name} details.") - # get run output - details = pf.get_details(base_run, all_results=True) - - # TODO: error handling like if the run failed because of rate limit. - - question = details["outputs.question"].tolist() - ground_truth = details["outputs.ground_truth"].tolist() - debug_info = details["outputs.debug_info"].tolist() - return [{"question": q, "ground_truth": g, "debug_info": d} for q, g, d in zip(question, ground_truth, debug_info)] - - -if __name__ == "__main__": - if os.path.isfile(CONFIG_FILE): - parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) - else: - raise Exception( - f"'{CONFIG_FILE}' does not exist. " - + "Please check if you are under the wrong directory or the file is missing." - ) - parser.add_argument("--should_skip_doc_split", action="store_true", help="Skip doc split or not") - parser.add_argument("--documents_folder", required=False, type=str, help="Documents folder path") - parser.add_argument("--document_chunk_size", required=False, type=int, help="Document chunk size, default is 1024") - parser.add_argument( - "--document_nodes_output_path", required=False, type=str, help="Document nodes output path, default is ./" - ) - parser.add_argument("--flow_folder", required=True, type=str, help="Test data generation flow folder path") - parser.add_argument( - "--flow_batch_run_size", - required=False, - type=int, - help="Test data generation flow batch run size, default is 16", - ) - parser.add_argument("--connection_name", required=True, type=str, help="Promptflow connection name") - parser.add_argument("--test_data_output_path", required=True, type=str, help="Test data output path.") - args = parser.parse_args() - if not (args.documents_folder or args.document_nodes_output_path): - parser.error("Either 'documents_folder' or 'document_nodes_output_path' should be specified.") - - output = args.document_nodes_output_path - if not args.should_skip_doc_split: - if not os.path.exists(args.document_nodes_output_path): - os.makedirs(args.document_nodes_output_path) - - output = split_document(args.document_chunk_size, args.documents_folder, args.document_nodes_output_path) - - pf = PFClient() - # TODO: error handling - batch_run = batch_run_flow( - pf, - args.flow_folder, - output, - args.flow_batch_run_size, - connection_name=args.connection_name, - ) - - test_data_set = get_batch_run_output(pf, batch_run) - - cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") - if not os.path.exists(args.test_data_output_path): - os.makedirs(args.test_data_output_path) - - output = os.path.join(args.test_data_output_path, "test-data-" + cur_time_str + ".jsonl") - clean_data_and_save(test_data_set, output) diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/__init__.py b/examples/test_data_gen/src/test_data_gen_pipeline/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/config.ini b/examples/test_data_gen/src/test_data_gen_pipeline/config.ini deleted file mode 100644 index 26537b1f243..00000000000 --- a/examples/test_data_gen/src/test_data_gen_pipeline/config.ini +++ /dev/null @@ -1,17 +0,0 @@ -subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" -resource_group = "promptflow" -; cspell: ignore yaopfeus -workspace_name = "yaopfeus" -aml_cluster = "cpu-cluster" -; cspell: ignore luyao -should_skip_doc_split = True -documents_folder = "D:\proj\github\ms\promptflow\docs\how-to-guides" -document_chunk_size = 1024 -document_nodes_file_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" -; test data gen flow configs -connection_name = "azure_open_ai_connection" -flow_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow\flow.dag.yaml" -; Parallel run step configs -prs_instance_count = 2 -prs_mini_batch_size = "10kb" -prs_max_concurrency_per_instance = 10 \ No newline at end of file diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py deleted file mode 100644 index 3b312c57f84..00000000000 --- a/examples/test_data_gen/src/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ /dev/null @@ -1,112 +0,0 @@ -import os - -import configargparse -from azure.ai.ml import Input, MLClient, dsl, load_component -from azure.identity import DefaultAzureCredential - -UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "src", "utils")) -if UTILS_PATH not in os.sys.path: - os.sys.path.insert(0, UTILS_PATH) - -from components import clean_test_data_set, document_split # noqa: E402 -from constants import CONNECTIONS_TEMPLATE # noqa: E402 - - -def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): - credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) - return MLClient( - credential=credential, - subscription_id=subscription_id, - resource_group_name=resource_group, - workspace_name=workspace_name, - ) - - -@dsl.pipeline( - non_pipeline_inputs=[ - "flow_yml_path", - "should_skip_doc_split", - "instance_count", - "mini_batch_size", - "max_concurrency_per_instance", - ] -) -def test_data_gen_pipeline_with_flow( - data_input: Input, - flow_yml_path: str, - connection_name: str, # ?? should we override here? - should_skip_doc_split: bool, - chunk_size=1024, - instance_count=1, - mini_batch_size="10kb", - max_concurrency_per_instance=2, -): - data = data_input if should_skip_doc_split else document_split(documents_folder=data_input, - chunk_size=chunk_size).outputs.document_node_output - flow_node = load_component(flow_yml_path)( - data=data, - text_chunk="${data.text_chunk}", - connections={key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items()}, - ) - - flow_node.mini_batch_size = mini_batch_size - flow_node.max_concurrency_per_instance = max_concurrency_per_instance - flow_node.set_resources(instance_count=instance_count) - - clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) - - -if __name__ == "__main__": - CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) - - if not os.path.isfile(CONFIG_FILE): - raise Exception(f"'{CONFIG_FILE}' does not exist. Please check your directory or if the file is missing.") - - parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) - parser.add_argument("--subscription_id", required=True, help="AzureML workspace subscription id") - parser.add_argument("--resource_group", required=True, help="AzureML workspace resource group name") - parser.add_argument("--workspace_name", required=True, help="AzureML workspace name") - parser.add_argument("--aml_cluster", required=True, help="AzureML cluster name") - parser.add_argument("--should_skip_doc_split", action="store_true", help="Skip doc split or not") - parser.add_argument("--document_nodes_file_path", help="Splitted document nodes file path") - parser.add_argument("--documents_folder", help="Documents folder path") - parser.add_argument("--document_chunk_size", type=int, help="Document chunk size") - parser.add_argument("--flow_path", required=True, help="Test data generation flow path") - parser.add_argument("--connection_name", required=True, help="Promptflow connection name") - parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") - parser.add_argument("--prs_mini_batch_size", help="Parallel run step mini batch size") - parser.add_argument("--prs_max_concurrency_per_instance", type=int, - help="Parallel run step max concurrency per instance") - - args = parser.parse_args() - - if args.should_skip_doc_split and not args.document_nodes_file_path: - parser.error("--document_nodes_file_path is required when --should_skip_doc_split is True") - elif not args.should_skip_doc_split and not args.documents_folder: - parser.error("--documents_folder is required when --should_skip_doc_split is False") - - ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) - - if args.should_skip_doc_split: - data_input = Input(path=args.document_nodes_file_path, type="uri_file") - else: - data_input = Input(path=args.documents_folder, type="uri_folder") - - prs_configs = { - "instance_count": args.prs_instance_count, - "mini_batch_size": args.prs_mini_batch_size, - "max_concurrency_per_instance": args.prs_max_concurrency_per_instance, - } - - pipeline_with_flow = test_data_gen_pipeline_with_flow( - data_input=data_input, - flow_yml_path=args.flow_path, - connection_name=args.connection_name, - should_skip_doc_split=args.should_skip_doc_split, - chunk_size=args.document_chunk_size, - **prs_configs, - ) - pipeline_with_flow.compute = args.aml_cluster - print("Completed to submit pipeline. Experiment Link: ", - ml_client.jobs.create_or_update(pipeline_with_flow).studio_url) diff --git a/examples/test_data_gen/src/utils/__init__.py b/examples/test_data_gen/src/utils/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/test_data_gen/src/__init__.py b/examples/test_data_gen/test_data_gen/__init__.py similarity index 100% rename from examples/test_data_gen/src/__init__.py rename to examples/test_data_gen/test_data_gen/__init__.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml similarity index 90% rename from examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml index 1cdc9a65037..a7608d9306e 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -5,6 +5,7 @@ inputs: text_chunk: type: string is_chat_input: false + default: asgfdsfdhgsfdh outputs: question: type: string @@ -55,8 +56,8 @@ nodes: type: code path: validate_and_generate_seed_question.py inputs: - connection: - model: gpt-4 + connection: open-ai-connection + model: gpt-4-1106-preview validate_text_trunk_prompt: ${validate_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} context: ${inputs.text_chunk} @@ -67,8 +68,8 @@ nodes: type: code path: validate_and_generate_test_question.py inputs: - connection: - model: gpt-4 + connection: open-ai-connection + model: gpt-4-1106-preview validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output} use_variants: false @@ -86,8 +87,8 @@ nodes: type: code path: validate_test_question.py inputs: - connection: - model: gpt-4 + connection: open-ai-connection + model: gpt-4-1106-preview question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} use_variants: false @@ -97,10 +98,10 @@ nodes: type: code path: generate_ground_truth.py inputs: - connection: + connection: open-ai-connection context: ${inputs.text_chunk} generate_ground_truth_prompt: ${generate_ground_truth_prompt.output} - model: gpt-4 + model: gpt-4-1106-preview question: ${validate_test_question.output} use_variants: false - name: generate_debug_info @@ -124,7 +125,7 @@ nodes: type: code path: validate_ground_truth.py inputs: - connection: - model: gpt-4 + connection: open-ai-connection + model: gpt-4-1106-preview ground_truth: ${generate_ground_truth.output} validate_ground_truth_prompt: ${validate_ground_truth_prompt.output} diff --git a/examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_debug_info.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/generate_debug_info.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_debug_info.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/generate_ground_truth_prompt.jinja2 rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 diff --git a/examples/test_data_gen/src/construct_test_data_flow/requirements.txt b/examples/test_data_gen/test_data_gen/construct_test_data_flow/requirements.txt similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/requirements.txt rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/requirements.txt diff --git a/examples/test_data_gen/src/construct_test_data_flow/seed_question_prompt.jinja2 b/examples/test_data_gen/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/seed_question_prompt.jinja2 rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 diff --git a/examples/test_data_gen/src/construct_test_data_flow/utils.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py similarity index 97% rename from examples/test_data_gen/src/construct_test_data_flow/utils.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py index a2d5d934407..3acda92eb70 100644 --- a/examples/test_data_gen/src/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py @@ -23,6 +23,7 @@ class ValidateObj: def llm_call(connection, model, prompt, response_format="text"): + response_format = "json_object" if response_format.lower() == "json" else response_format if isinstance(connection, AzureOpenAIConnection): return aoai_chat( connection=connection, diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_seed_question.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_and_generate_test_question.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth_prompt.jinja2 b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_ground_truth_prompt.jinja2 rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_question_prompt.jinja2 rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_test_question.py similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_test_question.py rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_test_question.py diff --git a/examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/src/construct_test_data_flow/validate_text_trunk_prompt.jinja2 rename to examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 diff --git a/examples/test_data_gen/src/test_data_gen_local/requirements.txt b/examples/test_data_gen/test_data_gen/requirements.txt similarity index 100% rename from examples/test_data_gen/src/test_data_gen_local/requirements.txt rename to examples/test_data_gen/test_data_gen/requirements.txt diff --git a/examples/test_data_gen/src/test_data_gen_pipeline/requirements.txt b/examples/test_data_gen/test_data_gen/requirements_cloud.txt similarity index 100% rename from examples/test_data_gen/src/test_data_gen_pipeline/requirements.txt rename to examples/test_data_gen/test_data_gen/requirements_cloud.txt diff --git a/examples/test_data_gen/test_data_gen/run.py b/examples/test_data_gen/test_data_gen/run.py new file mode 100644 index 00000000000..2c310cf2388 --- /dev/null +++ b/examples/test_data_gen/test_data_gen/run.py @@ -0,0 +1,242 @@ +import os +from datetime import datetime + +import configargparse +from azure.ai.ml import Input, MLClient, dsl, load_component +from azure.identity import DefaultAzureCredential + +from promptflow import PFClient +from promptflow.entities import Run + +CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.ini")) + +UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "test_data_gen", "utils")) +if UTILS_PATH not in os.sys.path: + os.sys.path.insert(0, UTILS_PATH) + +from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE # noqa: E402 +from common import split_document, clean_data_and_save # noqa: E402 +from components import clean_test_data_set, document_split # noqa: E402 + + +def batch_run_flow( + pf: PFClient, + flow_folder: str, + flow_input_data: str, + flow_batch_run_size: int, + connection_name: str = "azure_open_ai_connection", +): + print("#### Start to submit the batch run.") + base_run = pf.run( + flow=flow_folder, + data=flow_input_data, + stream=True, + environment_variables={ + "PF_WORKER_COUNT": str(flow_batch_run_size), + "PF_BATCH_METHOD": "spawn", + }, + connections={key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items()}, + column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, + debug=True, + ) + + print("#### Batch run is completed.") + + return base_run + + +def get_batch_run_output(pf: PFClient, base_run: Run): + print(f"#### Start to get batch run {base_run.name} details.") + details = pf.get_details(base_run, all_results=True) + question = details["outputs.question"].tolist() + ground_truth = details["outputs.ground_truth"].tolist() + debug_info = details["outputs.debug_info"].tolist() + return [{"question": q, "ground_truth": g, "debug_info": d} for q, g, d in zip(question, ground_truth, debug_info)] + + +def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): + credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) + return MLClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group, + workspace_name=workspace_name, + ) + + +@dsl.pipeline( + non_pipeline_inputs=[ + "flow_yml_path", + "should_skip_doc_split", + "instance_count", + "mini_batch_size", + "max_concurrency_per_instance", + ] +) +def test_data_gen_pipeline_with_flow( + data_input: Input, + flow_yml_path: str, + connection_name: str, + should_skip_doc_split: bool, + chunk_size=1024, + instance_count=1, + mini_batch_size="10kb", + max_concurrency_per_instance=2, +): + data = data_input if should_skip_doc_split else document_split(documents_folder=data_input, + chunk_size=chunk_size).outputs.document_node_output + flow_node = load_component(flow_yml_path)( + data=data, + text_chunk="${data.text_chunk}", + connections={key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items()}, + ) + + flow_node.mini_batch_size = mini_batch_size + flow_node.max_concurrency_per_instance = max_concurrency_per_instance + flow_node.set_resources(instance_count=instance_count) + + clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) + + +def run_local( + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + flow_batch_run_size, + connection_name, + output_folder, + should_skip_split +): + text_chunks_path = document_nodes_file + inner_folder = os.path.join(output_folder, datetime.now().strftime("%b-%d-%Y-%H-%M-%S")) + if not os.path.isdir(inner_folder): + os.makedirs(inner_folder) + + if not should_skip_split: + text_chunks_path = split_document(document_chunk_size, documents_folder, inner_folder) + + pf = PFClient() + batch_run = batch_run_flow( + pf, + flow_folder, + text_chunks_path, + flow_batch_run_size, + connection_name=connection_name, + ) + + test_data_set = get_batch_run_output(pf, batch_run) + clean_data_output = os.path.join(inner_folder, "test-data.jsonl") + clean_data_and_save(test_data_set, clean_data_output) + + +def run_cloud( + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + connection_name, + subscription_id, + resource_group, + workspace_name, + aml_cluster, + prs_instance_count, + prs_mini_batch_size, + prs_max_concurrency_per_instance, + should_skip_split +): + ml_client = get_ml_client(subscription_id, resource_group, workspace_name) + + if should_skip_split: + data_input = Input(path=document_nodes_file, type="uri_file") + else: + data_input = Input(path=documents_folder, type="uri_folder") + + prs_configs = { + "instance_count": prs_instance_count, + "mini_batch_size": prs_mini_batch_size, + "max_concurrency_per_instance": prs_max_concurrency_per_instance, + } + + pipeline_with_flow = test_data_gen_pipeline_with_flow( + data_input=data_input, + flow_yml_path=os.path.join(flow_folder, "flow.dag.yaml"), + connection_name=connection_name, + should_skip_doc_split=should_skip_split, + chunk_size=document_chunk_size, + **prs_configs, + ) + pipeline_with_flow.compute = aml_cluster + print("Completed to submit pipeline. Experiment Link: ", + ml_client.jobs.create_or_update(pipeline_with_flow).studio_url) + + +if __name__ == "__main__": + if os.path.isfile(CONFIG_FILE): + parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + else: + raise Exception( + f"'{CONFIG_FILE}' does not exist. " + + "Please check if you are under the wrong directory or the file is missing." + ) + + parser.add_argument('--cloud', action='store_true', help='cloud flag') + parser.add_argument("--documents_folder", type=str, help="Documents folder path") + parser.add_argument("--document_chunk_size", type=int, help="Document chunk size, default is 1024") + parser.add_argument( + "--document_nodes_file", type=str, help="Document nodes file, default is ./document_nodes.jsonl" + ) + + parser.add_argument("--flow_folder", required=True, type=str, help="Test data generation flow folder path") + parser.add_argument( + "--flow_batch_run_size", + type=int, + help="Test data generation flow batch run size, default is 16", + ) + parser.add_argument("--connection_name", required=True, type=str, help="Promptflow connection name") + # Configs for local + parser.add_argument("--output_folder", type=str, help="Output folder path.") + # Configs for cloud + parser.add_argument("--subscription_id", help="AzureML workspace subscription id") + parser.add_argument("--resource_group", help="AzureML workspace resource group name") + parser.add_argument("--workspace_name", help="AzureML workspace name") + parser.add_argument("--aml_cluster", help="AzureML cluster name") + parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") + parser.add_argument("--prs_mini_batch_size", help="Parallel run step mini batch size") + parser.add_argument("--prs_max_concurrency_per_instance", type=int, + help="Parallel run step max concurrency per instance") + args = parser.parse_args() + + should_skip_split_documents = False + if args.document_nodes_file and os.path.isfile(args.document_nodes_file): + should_skip_split_documents = True + elif not args.documents_folder or not os.path.isdir(args.documents_folder): + parser.error("Either 'documents_folder' or 'document_nodes_file' should be specified correctly.") + + if args.cloud: + run_cloud( + args.documents_folder, + args.document_chunk_size, + args.document_nodes_file, + args.flow_folder, + args.connection_name, + args.subscription_id, + args.resource_group, + args.workspace_name, + args.aml_cluster, + args.prs_instance_count, + args.prs_mini_batch_size, + args.prs_max_concurrency_per_instance, + should_skip_split_documents) + else: + run_local( + args.documents_folder, + args.document_chunk_size, + args.document_nodes_file, + args.flow_folder, + args.flow_batch_run_size, + args.connection_name, + args.output_folder, + should_skip_split_documents) diff --git a/examples/test_data_gen/src/test_data_gen_local/__init__.py b/examples/test_data_gen/test_data_gen/utils/__init__.py similarity index 100% rename from examples/test_data_gen/src/test_data_gen_local/__init__.py rename to examples/test_data_gen/test_data_gen/utils/__init__.py diff --git a/examples/test_data_gen/src/utils/common.py b/examples/test_data_gen/test_data_gen/utils/common.py similarity index 86% rename from examples/test_data_gen/src/utils/common.py rename to examples/test_data_gen/test_data_gen/utils/common.py index fad1425a685..6a26f8ecee8 100644 --- a/examples/test_data_gen/src/utils/common.py +++ b/examples/test_data_gen/test_data_gen/utils/common.py @@ -22,6 +22,7 @@ def split_document(chunk_size, documents_folder, document_node_output): documents = SimpleDirectoryReader( documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" ).load_data() + print(f"#### Collect {len(documents)} documents.") # Convert documents into nodes node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) @@ -31,7 +32,7 @@ def split_document(chunk_size, documents_folder, document_node_output): for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) - print(f"#### End to split the documents and generate {len(document_nodes)} text chunks.") + print(f"#### End to split the documents and generate {len(document_nodes)} document nodes.") return str((Path(document_node_output) / "document_nodes.jsonl")) @@ -48,4 +49,6 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): with open(test_data_output_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - print(f"#### Completed to generate the {len(cleaned_data)} test data and store to {test_data_output_path}.") + test_data_count = len(cleaned_data) + print( + f"#### Completed to clean {len(test_data_set) - test_data_count} invalid test data and collect {test_data_count} test data to {test_data_output_path}.") diff --git a/examples/test_data_gen/src/utils/components.py b/examples/test_data_gen/test_data_gen/utils/components.py similarity index 100% rename from examples/test_data_gen/src/utils/components.py rename to examples/test_data_gen/test_data_gen/utils/components.py diff --git a/examples/test_data_gen/src/utils/constants.py b/examples/test_data_gen/test_data_gen/utils/constants.py similarity index 100% rename from examples/test_data_gen/src/utils/constants.py rename to examples/test_data_gen/test_data_gen/utils/constants.py diff --git a/examples/test_data_gen/text-chunk-data.jsonl b/examples/test_data_gen/text-chunk-data.jsonl deleted file mode 100644 index 7dce5a6259a..00000000000 --- a/examples/test_data_gen/text-chunk-data.jsonl +++ /dev/null @@ -1,531 +0,0 @@ -{"text_chunk": "Connections\n\nConnections are for storing information about how to access external services like LLMs: endpoint, api keys etc.\n\n- In your local development environment, the connections are persisted in your local machine with keys encrypted.\n- In Azure AI, connections can be configured to be shared across the entire workspace. Secrets associated with connections are securely persisted in the corresponding Azure Key Vault, adhering to robust security and compliance standards.\n\nPrompt flow provides a variety of pre-built connections, including Azure Open AI, Open AI, etc. These pre-built connections enable seamless integration with these resources within the built-in tools. Additionally, you have the flexibility to create custom connection types using key-value pairs, empowering them to tailor the connections to their specific requirements, particularly in Python tools.\n\n| Connection type | Built-in tools |\n| ------------------------------------------------------------ | ------------------------------- |\n| Azure Open AI | LLM or Python |\n| Open AI | LLM or Python |\n| Cognitive Search | Vector DB Lookup or Python |\n| Serp | Serp API or Python |\n| Custom | Python |\n\nBy leveraging connections in prompt flow, you can easily establish and manage connections to external APIs and data sources, facilitating efficient data exchange and interaction within their AI applications."} -{"text_chunk": "Next steps\n\n- Create connections"} -{"text_chunk": "Flows\n\nA flow in prompt flow is a DAG of functions (we call them tools). These functions/tools connected via input/output dependencies and executed based on the topology by prompt flow executor.\n\nA flow is represented as a YAML file and can be visualized with our Prompt flow for VS Code extension. Here is an example:\n\n!flow_dag"} -{"text_chunk": "Flow types\n\nPrompt flow has three flow types:\n\n- **Standard flow** and **Chat flow**: these two are for you to develop your LLM application. The primary difference between the two lies in the additional support provided by the \"Chat Flow\" for chat applications. For instance, you can define chat_history, chat_input, and chat_output for your flow. The prompt flow, in turn, will offer a chat-like experience (including conversation history) during the development of the flow. Moreover, it also provides a sample chat application for deployment purposes.\n- **Evaluation flow** is for you to test/evaluate the quality of your LLM application (standard/chat flow). It usually run on the outputs of standard/chat flow, and compute some metrics that can be used to determine whether the standard/chat flow performs well. E.g. is the answer accurate? is the answer fact-based?"} -{"text_chunk": "When to use standard flow vs. chat flow?\n\nAs a general guideline, if you are building a chatbot that needs to maintain conversation history, try chat flow. In most other cases, standard flow should serve your needs.\n\nOur examples should also give you an idea when to use what:\n- examples/flows/standard\n- examples/flows/chat"} -{"text_chunk": "Next steps\n\n- Quick start\n- Initialize and test a flow\n- Run and evaluate a flow\n- Tune prompts using variants"} -{"text_chunk": "Tools\n\nPrompt flow provides 3 basic tools:\n- LLM: The LLM tool allows you to write custom prompts and leverage large language models to achieve specific goals, such as summarizing articles, generating customer support responses, and more.\n- Python: The Python tool enables you to write custom Python functions to perform various tasks, such as fetching web pages, processing intermediate data, calling third-party APIs, and more.\n- Prompt: The Prompt tool allows you to prepare a prompt as a string for more complex use cases or for use in conjunction with other prompt tools or python tools."} -{"text_chunk": "More tools\n\nOur partners also contributes other useful tools for advanced scenarios, here are some links:\n- Vector DB Lookup: vector search tool that allows users to search top k similar vectors from vector database.\n- Faiss Index Lookup: querying within a user-provided Faiss-based vector store."} -{"text_chunk": "Custom tools\n\nYou can create your own tools that can be shared with your team or anyone in the world. \nLearn more on Create and Use Tool Package"} -{"text_chunk": "Next steps\n\nFor more information on the available tools and their usage, visit the our reference doc."} -{"text_chunk": "Variants\n\nA variant refers to a specific version of a tool node that has distinct settings. Currently, variants are supported only in the LLM tool. For example, in the LLM tool, a new variant can represent either a different prompt content or different connection settings.\n\nSuppose you want to generate a summary of a news article. You can set different variants of prompts and settings like this:\n\n| Variants | Prompt | Connection settings |\n| --------- | ------------------------------------------------------------ | ------------------- |\n| Variant 0 | `Summary: {{input sentences}}` | Temperature = 1 |\n| Variant 1 | `Summary: {{input sentences}}` | Temperature = 0.7 |\n| Variant 2 | `What is the main point of this article? {{input sentences}}` | Temperature = 1 |\n| Variant 3 | `What is the main point of this article? {{input sentences}}` | Temperature = 0.7 |\n\nBy utilizing different variants of prompts and settings, you can explore how the model responds to various inputs and outputs, enabling you to discover the most suitable combination for your requirements."} -{"text_chunk": "Benefits of using variants\n\n- **Enhance the quality of your LLM generation**: By creating multiple variants of the same LLM node with diverse prompts and configurations, you can identify the optimal combination that produces high-quality content aligned with your needs.\n- **Save time and effort**: Even slight modifications to a prompt can yield significantly different results. It's crucial to track and compare the performance of each prompt version. With variants, you can easily manage the historical versions of your LLM nodes, facilitating updates based on any variant without the risk of forgetting previous iterations. This saves you time and effort in managing prompt tuning history.\n- **Boost productivity**: Variants streamline the optimization process for LLM nodes, making it simpler to create and manage multiple variations. You can achieve improved results in less time, thereby increasing your overall productivity.\n- **Facilitate easy comparison**: You can effortlessly compare the results obtained from different variants side by side, enabling you to make data-driven decisions regarding the variant that generates the best outcomes."} -{"text_chunk": "Next steps\n\n- Tune prompts with variants"} -{"text_chunk": "Design principles\n\nWhen we started this project, LangChain already became popular esp. after the ChatGPT launch. One of the questions we\u2019ve been asked is what\u2019s the difference between prompt flow and LangChain. This article is to elucidate the reasons for building prompt flow and the deliberate design choices we have made. To put it succinctly, prompt flow is a suite of development tools for you to build LLM apps with a strong emphasis of quality through experimentations, not a framework - which LangChain is.\n\nWhile LLM apps are mostly in exploration stage, Microsoft started in this area a bit earlier and we\u2019ve had the opportunity to observe how developers are integrating LLMs into existing systems or build new applications. These invaluable insights have shaped the fundamental design principles of prompt flow."} -{"text_chunk": "1. Expose the prompts vs. hiding them\n\nThe core essence of LLM applications lies in the prompts themselves, at least for today. When developing a reasonably complex LLM application, the majority of development work should be \u201ctuning\u201d the prompts (note the intentional use of the term \"tuning,\" which we will delve into further later on). Any framework or tool trying to help in this space should focus on making prompt tuning easier and more straightforward. On the other hand, prompts are very volatile, it's unlikely to write a single prompt that can work across different models or even different version of same models. Building a successful LLM-based application, you have to understand every prompt introduced, so that you can tune it when necessary. LLM is simply not powerful or deterministic enough that you can use a prompt written by others like you use libraries in traditional programming languages.\n\nIn this context, any design that tries to provide a smart function or agent by encapsulating a few prompts in a library is unlikely to yield favorable results in real-world scenarios. And hiding prompts inside a library\u2019s code base only makes it\u2019s hard for people to improve or tailor the prompts to suit their specific needs.\n\nPrompt flow, being positioned as a tool, refrains from wrapping any prompts within its core codebase. The only place you will see prompts are our sample flows, which are, of course, available for adoption and utilization. Every prompt should be authored and controlled by the developers themselves, rather than relying on us."} -{"text_chunk": "2. A new way of work\n\nLLMs possess remarkable capabilities that enable developers to enhance their applications without delving deep into the intricacies of machine learning. In the meantime, LLMs make these apps more stochastic, which pose new challenges to application development. Merely asserting \"no exception\" or \"result == x\" in gated tests is no longer sufficient. Adopting a new methodology and employing new tools becomes imperative to ensure the quality of LLM applications \u2014 an entirely novel way of working is required.\n\nAt the center of this paradigm shift is evaluation, a term frequently used in machine learning space, refers to the process of assessing the performance and quality of a trained model. It involves measuring how well the model performs on a given task or dataset, which plays a pivotal role in understanding the model's strengths, weaknesses, and overall effectiveness. Evaluation metrics and techniques vary depending on the specific task and problem domain. Some common metrics include accuracy, precision and recall, you probably already familiar with. Now the LLM apps share similarities with machine learning models, they requires an evaluation-centric approach integrated into the development workflow, with a robust set of metrics and evaluation forming the foundation for ensuring the quality of LLM applications.\n\nPrompt flow offers a range of tools to streamline the new way of work:\n\n* Develop your evaluation program as Evaluation flow to calculate metrics for your app/flow, learn from our sample evaluation flows.\n* Iterate on your application flow and run evaluation flows via the SDK/CLI, allowing you to compare metrics and choose the optimal candidate for release. These iterations include trying different prompts, different LLM parameters like temperature etc. - this is referred as \u201ctuning\u201d process earlier, or sometime referred as experimentation.\n* Integrate the evaluation into your CI/CD pipeline, aligning the assertions in your gated tests with the selected metrics.\n\n\nPrompt flow introduces two conceptual components to facilitate this workflow:\n\n* Evaluation flow: a flow type that indicates this flow is not for deploy or integrate into your app, it\u2019s for evaluating an app/flow performance.\n* Run: every time you run your flow with data, or run an evaluation on the output of a flow, a Run object is created to manage the history and allow for comparison and additional analysis.\n\nWhile new concepts introduce additional cognitive load, we firmly believe they hold greater importance compared to abstracting different LLM APIs or vector database APIs."} -{"text_chunk": "3. Optimize for \u201cvisibility\u201d\n\nThere are quite some interesting application patterns emerging because of LLMs, like Retrieval Augmented Generation (RAG), ReAct and more. Though how LLMs work may remain enigmatic to many developers, how LLM apps work is not - they essentially involve a series of calls to external services such as LLMs, databases, and search engines, all glued together. Architecturally there isn\u2019t much new, patterns like RAG and ReAct are both straightforward to implement once a developer understands what they are - plain Python programs with API calls to external services can totally serve the purpose effectively.\n\nBy observing many internal use cases, we learned that deeper insight into the detail of the execution is critical. Establishing a systematic method for tracking interactions with external systems is one of design priority. Consequently, We adopted an unconventional approach - prompt flow has a YAML file describing how function calls (we call them Tools) are executed and connected into a Directed Acyclic Graph (DAG). \n\nThis approach offers several key benefits, primarily centered around **enhanced visibility**:\n1) During development, your flow can be visualized in an intelligible manner, enabling clear identification of any faulty components. As a byproduct, you obtain an architecturally descriptive diagram that can be shared with others.\n2) Each node in the flow has it\u2019s internal detail visualized in a consistent way.\n3) Single nodes can be individually run or debugged without the need to rerun previous nodes.\n\n\n!promptflow-dag\n\nThe emphasis on visibility in prompt flow's design helps developers to gain a comprehensive understanding of the intricate details of their applications. This, in turn, empowers developers to engage in effective troubleshooting and optimization.\n\nDespite there're some control flow features like \"activate-when\" to serve the needs of branches/switch-case, we do not intend to make Flow itself Turing-complete. If you want to develop an agent which is fully dynamic and guided by LLM, leveraging Semantic Kernel together with prompt flow would be a favorable option."} -{"text_chunk": "Dev Setup"} -{"text_chunk": "Set up process\n\n- First create a new conda environment. Please specify python version as 3.9.\n `conda create -n python=3.9`.\n- Activate the env you created.\n- Set environment variable `PYTHONPATH` in your new conda environment.\n `conda env config vars set PYTHONPATH=\\promptflow`.\n Once you have set the environment variable, you have to reactivate your environment.\n `conda activate `.\n- In root folder, run `python scripts/building/dev_setup.py --promptflow-extra-deps azure` to install the package and dependencies."} -{"text_chunk": "How to run tests"} -{"text_chunk": "Set up your secrets\n\n`dev-connections.json.example` is a template about connections provided in `src/promptflow`. You can follow these steps to refer to this template to configure your connection for the test cases:\n1. `cd ./src/promptflow`\n2. Run the command `cp dev-connections.json.example connections.json`;\n3. Replace the values in the json file with your connection info;\n4. Set the environment `PROMPTFLOW_CONNECTIONS='connections.json'`;\n\nAfter above setup process is finished. You can use `pytest` command to run test, for example in root folder you can:"} -{"text_chunk": "Run tests via command\n\n- Run all tests under a folder: `pytest src/promptflow/tests -v`\n- Run a single test: ` pytest src/promptflow/tests/promptflow_test/e2etests/test_executor.py::TestExecutor::test_executor_basic_flow -v`"} -{"text_chunk": "Run tests in VSCode\n\n1. Set up your python interperter\n\n- Open the Command Palette (Ctrl+Shift+P) and select `Python: Select Interpreter`.\n\n!img0\n\n- Select existing conda env which you created previously.\n\n!img1\n\n2. Set up your test framework and directory\n\n- Open the Command Palette (Ctrl+Shift+P) and select `Python: Configure Tests`.\n\n!img2\n\n- Select `pytest` as test framework.\n\n!img3\n\n- Select `Root directory` as test directory.\n\n!img4\n\n3. Exclude specific test folders.\n\nYou can exclude specific test folders if you don't have some extra dependency to avoid VS Code's test discovery fail.\nFor example, if you don't have azure dependency, you can exclude `sdk_cli_azure_test`.\nOpen `.vscode/settings.json`, write `\"--ignore=src/promptflow/tests/sdk_cli_azure_test\"` to `\"python.testing.pytestArgs\"`.\n\n!img6\n\n4. Click the `Run Test` button on the left\n\n!img5"} -{"text_chunk": "Run tests in pycharm\n\n1. Set up your pycharm python interpreter\n\n!img0\n\n2. Select existing conda env which you created previously\n\n!img1\n\n3. Run test, right-click the test name to run, or click the green arrow button on the left.\n\n!img2"} -{"text_chunk": "Record and replay tests\n\nPlease refer to Replay End-to-End Tests to learn how to record and replay tests."} -{"text_chunk": "How to write docstring.\n\nA clear and consistent API documentation is crucial for the usability and maintainability of our codebase. Please refer to API Documentation Guidelines to learn how to write docstring when developing the project."} -{"text_chunk": "How to write tests\n\n- Put all test data/configs under `src/promptflow/tests/test_configs`.\n- Write unit tests:\n - Flow run: `src/promptflow/tests/sdk_cli_test/unittest/`\n - Flow run in azure: `src/promptflow/tests/sdk_cli_azure_test/unittest/`\n- Write e2e tests:\n - Flow run: `src/promptflow/tests/sdk_cli_test/e2etests/`\n - Flow run in azure: `src/promptflow/tests/sdk_cli_azure_test/e2etests/`\n- Test file name and the test case name all start with `test_`.\n- A basic test example, see test_connection.py."} -{"text_chunk": "Test structure\n\nCurrently all tests are under `src/promptflow/tests/` folder:\n\n- tests/\n - promptflow/\n - sdk_cli_test/\n - e2etests/\n - unittests/\n - sdk_cli_azure_test/\n - e2etests/\n - unittests/\n - test_configs/\n - connections/\n - datas/\n - flows/\n - runs/\n - wrong_flows/\n - wrong_tools/\n\nWhen you want to add tests for a new feature, you can add new test file let's say a e2e test file `test_construction.py`\nunder `tests/promptflow/**/e2etests/`.\n\nOnce the project gets more complicated or anytime you find it necessary to add new test folder and test configs for\na specific feature, feel free to split the `promptflow` to more folders, for example:\n\n- tests/\n - (Test folder name)/\n - e2etests/\n - test_xxx.py\n - unittests/\n - test_xxx.py\n - test_configs/\n - (Data or config folder name)/"} -{"text_chunk": "Promptflow Reference Documentation Guide"} -{"text_chunk": "Overview\n\nThis guide describes how to author Python docstrings for promptflow public interfaces. See our doc site at Promptflow API reference documentation."} -{"text_chunk": "Principles\n\n- **Coverage**: Every public object must have a docstring. For private objects, docstrings are encouraged but not required.\n- **Style**: All docstrings should be written in Sphinx style noting all types and if any exceptions are raised.\n- **Relevance**: The documentation is up-to-date and relevant to the current version of the product.\n- **Clarity**: The documentation is written in clear, concise language that is easy to understand.\n- **Consistency**: The documentation has a consistent format and structure, making it easy to navigate and follow."} -{"text_chunk": "How to write the docstring\n\nFirst please read through Sphinx style to have a basic understanding of sphinx style docstring."} -{"text_chunk": "Write class docstring\n\nLet's start with a class example:\n```python\nfrom typing import Dict, Optional, Union\nfrom promptflow import PFClient\n\nclass MyClass:\n \"\"\"One-line summary of the class.\n\n More detailed explanation of the class. May include below notes, admonitions, code blocks.\n\n .. note::\n\n Here are some notes to show, with a nested python code block:\n\n .. code-block:: python\n\n from promptflow import MyClass, PFClient\n obj = MyClass(PFClient())\n\n .. admonition:: [Title of the admonition]\n\n Here are some admonitions to show.\n\n :param client: Descrition of the client.\n :type client: ~promptflow.PFClient\n :param param_int: Description of the parameter.\n :type param_int: Optional[int]\n :param param_str: Description of the parameter.\n :type param_str: Optional[str]\n :param param_dict: Description of the parameter.\n :type param_dict: Optional[Dict[str, str]]\n \"\"\"\n def __init__(\n client: PFClient,\n param_int: Optional[int] = None,\n param_str: Optional[str] = None,\n param_dict: Optional[Dict[str, str]] = None,\n ) -> None:\n \"\"\"No docstring for __init__, it should be written in class definition above.\"\"\"\n ...\n\n\n```\n\n**Notes**:\n\n1. One-line summary is required. It should be clear and concise.\n2. Detailed explanation is encouraged but not required. This part may or may not include notes, admonitions and code blocks.\n - The format like `.. note::` is called `directive`. Directives are a mechanism to extend the content of reStructuredText. Every directive declares a block of content with specific role. Start a new line with `.. directive_name::` to use the directive. \n - The directives used in the sample(`note/admonition/code-block`) should be enough for basic usage of docstring in our project. But you are welcomed to explore more Directives.\n3. Parameter description and type is required.\n - A pair of `:param [ParamName]:` and `:type [ParamName]:` is required.\n - If the type is a promptflow public class, use the `full path to the class` and prepend it with a \"~\". This will create a link when the documentation is rendered on the doc site that will take the user to the class reference documentation for more information.\n ```text\n :param client: Descrition of the client.\n :type client: ~promptflow.PFClient\n ```\n - Use `Union/Optional` when appropriate in function declaration. And use the same annotaion after `:type [ParamName]:`\n ```text\n :type param_int: Optional[int]\n ```\n4. For classes, include docstring in definition only. If you include a docstring in both the class definition and the constructor (init method) docstrings, it will show up twice in the reference docs.\n5. Constructors (def `__init__`) should return `None`, per PEP 484 standards.\n6. To create a link for promptflow class on our doc site. `~promptflow.xxx.MyClass` alone only works after `:type [ParamName]` and `:rtype:`. If you want to achieve the same effect in docstring summary, you should use it with `:class:`:\n ```python\n \"\"\"\n An example to achieve link effect in summary for :class:`~promptflow.xxx.MyClass`\n For function, use :meth:`~promptflow.xxx.my_func`\n \"\"\"\n ```\n\n7. There are some tricks to highlight the content in your docstring:\n - Single backticks (`): Single backticks are used to represent inline code elements within the text. It is typically used to highlight function names, variable names, or any other code elements within the documentation.\n - Double backticks(``): Double backticks are typically used to highlight a literal value.\n\n8. If there are any class level constants you don't want to expose to doc site, make sure to add `_` in front of the constant to hide it."} -{"text_chunk": "Write function docstring\n\n```python\nfrom typing import Optional\n\ndef my_method(param_int: Optional[int] = None) -> int:\n \"\"\"One-line summary\n\n Detailed explanations.\n\n :param param_int: Description of the parameter.\n :type param_int: int\n :raises [ErrorType1]: [ErrorDescription1]\n :raises [ErrorType2]: [ErrorDescription2]\n :return: Description of the return value.\n :rtype: int\n \"\"\"\n ...\n```\n\nIn addition to `class docstring` notes:\n\n1. Function docstring should include return values.\n - If return type is promptflow class, we should also use `~promptflow.xxx.[ClassName]`.\n2. Function docstring should include exceptions that may be raised in this function.\n - If exception type is `PromptflowException`, use `~promptflow.xxx.[ExceptionName]`\n - If multiple exceptions are raised, just add new lines of `:raises`, see the example above."} -{"text_chunk": "How to build doc site locally\n\nYou can build the documentation site locally to preview the final effect of your docstring on the rendered site. This will provide you with a clear understanding of how your docstring will appear on our site once your changes are merged into the main branch.\n\n1. Setup your dev environment, see dev_setup for details. Sphinx will load all source code to process docstring.\n - Skip this step if you just want to build the doc site without reference doc, but do remove `-WithReferenceDoc` from the command in step 3.\n2. Install `langchain` package since it is used in our code but not covered in `dev_setup`.\n3. Open a `powershell`, activate the conda env and navigate to `/scripts/docs` , run `doc_generation.ps1`:\n ```pwsh\n cd scripts\\docs\n .\\doc_generation.ps1 -WithReferenceDoc -WarningAsError\n ```\n - For the first time you execute this command, it will take some time to install `sphinx` dependencies. After the initial installation, next time you can add param `-SkipInstall` to above command to save some time for dependency check.\n4. Check warnings/errors in the build log, fix them if any, then build again.\n5. Open `scripts/docs/_build/index.html` to preview the local doc site."} -{"text_chunk": "Additional comments\n\n- **Utilities**: The autoDocstring VSCode extension or GitHub Copilot can help autocomplete in this style for you.\n\n- **Advanced principles**\n - Accuracy: The documentation accurately reflects the features and functionality of the product.\n - Completeness: The documentation covers all relevant features and functionality of the product.\n - Demonstration: Every docstring should include an up-to-date code snippet that demonstrates how to use the product effectively."} -{"text_chunk": "References\n\n- AzureML v2 Reference Documentation Guide\n- Azure SDK for Python documentation guidelines\n- How to document a Python API"} -{"text_chunk": "Replay end-to-end tests\n\n* This document introduces replay tests for those located in sdk_cli_azure_test and sdk_cli_test.\n* The primary purpose of replay tests is to avoid the need for credentials, Azure workspaces, OpenAI tokens, and to directly test prompt flow behavior.\n* Although there are different techniques behind recording/replaying, there are some common steps to run the tests in replay mode.\n* The key handle of replay tests is the environment variable `PROMPT_FLOW_TEST_MODE`."} -{"text_chunk": "How to run tests in replay mode\n\nAfter cloning the full repo and setting up the proper test environment following dev_setup.md, run the following command in the root directory of the repo:\n\n1. If you have changed/affected tests in __sdk_cli_test__ : Copy or rename the file dev-connections.json.example to `connections.json` in the same folder.\n2. In your Python environment, set the environment variable `PROMPT_FLOW_TEST_MODE` to `'replay'` and run the test(s).\n\nThese tests should work properly without any real connection settings."} -{"text_chunk": "Test modes\n\nThere are 3 representative values of the environment variable `PROMPT_FLOW_TEST_MODE`\n- `live`: Tests run against the real backend, which is the way traditional end-to-end tests do.\n- `record`: Tests run against the real backend, and network traffic will be sanitized (filter sensitive and unnecessary requests/responses) and recorded to local files (recordings).\n- `replay`: There is no real network traffic between SDK/CLI and the backend, tests run against local recordings."} -{"text_chunk": "Update test recordings\n\nTo record a test, don\u2019t forget to clone the full repo and set up the proper test environment following dev_setup.md:\n1. Prepare some data.\n * If you have changed/affected tests in __sdk_cli_test__: Copy or rename the file dev-connections.json.example to `connections.json` in the same folder.\n * If you have changed/affected tests in __sdk_cli_azure_test__: prepare your Azure ML workspace, make sure your Azure CLI logged in, and set the environment variable `PROMPT_FLOW_SUBSCRIPTION_ID`, `PROMPT_FLOW_RESOURCE_GROUP_NAME`, `PROMPT_FLOW_WORKSPACE_NAME` and `PROMPT_FLOW_RUNTIME_NAME` (if needed) pointing to your workspace.\n2. Record the test.\n * Specify the environment variable `PROMPT_FLOW_TEST_MODE` to `'record'`. If you have a `.env` file, we recommend specifying it there. Here is an example .env file. Then, just run the test that you want to record.\n3. Once the test completed.\n * If you have changed/affected tests in __sdk_cli_azure_test__: There should be one new YAML file located in `src/promptflow/tests/test_configs/recordings/`, containing the network traffic of the test.\n * If you have changed/affected tests in __sdk_cli_test__: There may be changes in the folder `src/promptflow/tests/test_configs/node_recordings/`. Don\u2019t worry if there are no changes, because similar LLM calls may have been recorded before."} -{"text_chunk": "Techniques behind replay test"} -{"text_chunk": "Sdk_cli_azure_test\n\nEnd-to-end tests for pfazure aim to test the behavior of the PromptFlow SDK/CLI as it interacts with the service. This process can be time-consuming, error-prone, and require credentials (which are unavailable to pull requests from forked repositories); all of these go against our intention for a smooth development experience.\n\nTherefore, we introduce replay tests, which leverage VCR.py to record all required network traffic to local files and replay during tests. In this way, we avoid the need for credentials, speed up, and stabilize the test process."} -{"text_chunk": "Sdk_cli_test\n\nsdk_cli_test often doesn\u2019t use a real backend. It will directly invokes LLM calls from localhost. Thus the key target of replay tests is to avoid the need for OpenAI tokens. If you have OpenAI / Azure OpenAI tokens yourself, you can try recording the tests. Record Storage will not record your own LLM connection, but only the inputs and outputs of the LLM calls.\n\nThere are also limitations. Currently, recorded calls are:\n* AzureOpenAI calls\n* OpenAI calls\n* tool name \"fetch_text_content_from_url\" and tool name \"my_python_tool\""} -{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow."} -{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`."} -{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::"} -{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed"} -{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example"} -{"text_chunk": "Next steps\n\n- Run and evaluate a flow"} -{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash"} -{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::"} -{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes."} -{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image."} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker."} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files"} -{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification."} -{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker."} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```"} -{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container."} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work."} -{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash"} -{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```"} -{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes."} -{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment."} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker."} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files"} -{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions."} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```"} -{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```"} -{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`."} -{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work."} -{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```"} -{"text_chunk": "Next steps\n- Try the example here."} -{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them."} -{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```"} -{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files."} -{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```"} -{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec"} -{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```"} -{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application."} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```"} -{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux)."} -{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13."} -{"text_chunk": "Next steps\n- Try the example here"} -{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema."} -{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools."} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools."} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow."} -{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```"} -{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow."} -{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data."} -{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow."} -{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs."} -{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`."} -{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img"} -{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img"} -{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema."} -{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types."} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc."} -{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::"} -{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool"} -{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::"} -{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details."} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface."} -{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```"} -{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```"} -{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together."} -{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly."} -{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly."} -{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly."} -{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::"} -{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud."} -{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon."} -{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference."} -{"text_chunk": "Add tool icon with _icon_ parameter"} -{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```"} -{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension"} -{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```"} -{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```"} -{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode."} -{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field."} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later."} -{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```"} -{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag"} -{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```"} -{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list"} -{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section."} -{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```"} -{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure."} -{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`."} -{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension"} -{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed."} -{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one."} -{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs"} -{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools."} -{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} -{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```"} -{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png"} -{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections."} -{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool."} -{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} -{"text_chunk": "Create a tool input with dynamic listing"} -{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```"} -{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```"} -{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details."} -{"text_chunk": "FAQs"} -{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure"} -{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause."} -{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection."} -{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections."} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} -{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation."} -{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:"} -{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow"} -{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow"} -{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```"} -{"text_chunk": "FAQs"} -{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible."} -{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`."} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later."} -{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```"} -{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool"} -{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow."} -{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later."} -{"text_chunk": "Using File Path as Package Tool Input"} -{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool"} -{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath"} -{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package."} -{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow"} -{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool"} -{"text_chunk": "FAQ"} -{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above."} -{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints."} -{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png"} -{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page."} -{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:"} -{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response."} -{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request."} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```"} -{"text_chunk": "4. The chat continues in a similar way."} -{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user."} -{"text_chunk": "How to consume the server-sent events"} -{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```"} -{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example."} -{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app"} -{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response."} -{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```"} -{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```"} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```"} -{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::"} -{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption."} -{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```"} -{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`."} -{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)"} -{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```"} -{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing."} -{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\""} -{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage."} -{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow"} -{"text_chunk": "Frequency asked questions (FAQ)"} -{"text_chunk": "General"} -{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches."} -{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details."} -{"text_chunk": "Troubleshooting"} -{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring."} -{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us."} -{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible."} -{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img"} -{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork."} -{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```"} -{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it."} -{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow."} -{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash"} -{"text_chunk": "Create a flow\npf flow init --flow"} -{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder"} -{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash"} -{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files"} -{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow."} -{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::"} -{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash"} -{"text_chunk": "Test flow\npf flow test --flow"} -{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::"} -{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash"} -{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} -{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::"} -{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash"} -{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::"} -{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::"} -{"text_chunk": "Next steps\n\n- Add conditional control to a flow"} -{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::"} -{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections."} -{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash"} -{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key="} -{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} -{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)"} -{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)"} -{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)"} -{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::"} -{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash"} -{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'"} -{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python"} -{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)"} -{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::"} -{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} -{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} -{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} -{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::"} -{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI."} -{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run"} -{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash"} -{"text_chunk": "create the flow run\npf run create -f"} -{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)"} -{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::"} -{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} -{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} -{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::"} -{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::"} -{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::"} -{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::"} -{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} -{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} -{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::"} -{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data."} -{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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."} -{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image."} -{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model."} -{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario."} -{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```"} -{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension."} -{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash"} -{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```"} -{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details."} -{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```"} -{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```"} -{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section."} -{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode"} -{"text_chunk": "Develop and test your flow"} -{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow."} -{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection"} -{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections."} -{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name"} -{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")"} -{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow."} -{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics."} -{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow."} -{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column."} -{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow"} -{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data"} -{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data."} -{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli."} -{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```"} -{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```"} -{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values."} -{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections."} -{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::"} -{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more."} -{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first."} -{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence."} -{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\""} -{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run."} -{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI"} -{"text_chunk": "Azure AI Language\nAzure AI Language enables users with task-oriented and optimized pre-trained language models to effectively understand documents and conversations. This Prompt flow tool is a wrapper for various Azure AI Language APIs. The current list of supported capabilities is as follows:\n\n| Name | Description |\n|-------------------------------------------|-------------------------------------------------------|\n| Abstractive Summarization | Generate abstractive summaries from documents. |\n| Extractive Summarization | Extract summaries from documents. |\n| Conversation Summarization | Summarize conversations. |\n| Entity Recognition | Recognize and categorize entities in documents. |\n| Key Phrase Extraction | Extract key phrases from documents. |\n| Language Detection | Detect the language of documents. |\n| PII Entity Recognition | Recognize and redact PII entities in documents. |\n| Sentiment Analysis | Analyze the sentiment of documents. |\n| Conversational Language Understanding | Predict intents and entities from user's utterances. |\n| Translator | Translate documents. |"} -{"text_chunk": "Requirements\n- For AzureML users: \n follow this wiki, starting from `Prepare runtime`. Note that the PyPi package name is `promptflow-azure-ai-language`.\n- For local users: \n ```\n pip install promptflow-azure-ai-language\n ```"} -{"text_chunk": "Prerequisites\nThe tool calls APIs from Azure AI Language. To use it, you must create a connection to an Azure AI Language resource. Create a Language resource first, if necessary.\n- In Prompt flow, add a new `CustomConnection`.\n - Under the `secrets` field, specify the resource's API key: `api_key: `\n - Under the `configs` field, specify the resource's endpoint: `endpoint: `\n\nTo use the `Translator` tool, you must set up an additional connection to an Azure AI Translator resource. Create a Translator resource first, if necessary.\n- In Prompt flow, add a new `CustomConnection`.\n - Under the `secrets` field, specify the resource's API key: `api_key: `\n - Under the `configs` field, specify the resource's endpoint: `endpoint: `\n - If your Translator Resource is regional and non-global, specify its region under `configs` as well: `region: `"} -{"text_chunk": "Inputs\nThe tool accepts the following inputs:\n\n- **Abstractive Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | query | string | The query used to structure summarization. | Yes |\n | summary_length | string (enum) | The desired summary length. Enum values are `short`, `medium`, and `long`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Extractive Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | query | string | The query used to structure summarization. | Yes |\n | sentence_count | int | The desired number of output summary sentences. Default value is `3`. | No |\n | sort_by | string (enum) | The sorting criteria for extractive summarization results. Enum values are `Offset` to sort results in order of appearance in the text and `Rank` to sort results in order of importance (i.e. rank score) according to model. Default value is `Offset`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Conversation Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. Text should be of the following form: `: \\n : \\n ...` | Yes |\n | modality | string (enum) | The modality of the input text. Enum values are `text` for input from a text source, and `transcript` for input from a transcript source. | Yes |\n | summary_aspect | string (enum) | The desired summary \"aspect\" to obtain. Enum values are `chapterTitle` to obtain the chapter title of any conversation, `issue` to obtain the summary of issues in transcripts of web chats and service calls between customer-service agents and customers, `narrative` to obtain the generic summary of any conversation, `resolution` to obtain the summary of resolutions in transcripts of web chats and service calls between customer-service agents and customers, `recap` to obtain a general summary, and `follow-up tasks` to obtain a summary of follow-up or action items. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Entity Recognition**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Key Phrase Extraction**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text."} -{"text_chunk": "| Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Language Detection**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | text | string | The input text. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **PII Entity Recognition**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | domain | string (enum) | The PII domain used for PII Entity Recognition. Enum values are `none` for no domain, or `phi` to indicate that entities in the Personal Health domain should be redacted. Default value is `none`. | No |\n | categories | list[string] | Describes the PII categories to return. Default value is `[]`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Sentiment Analysis**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | opinion_mining | bool | Should opinion mining be enabled. Default value is `False`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Conversational Language Understanding**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | utterances | string | A single user utterance or a json array of user utterances. | Yes |\n | project_name | string | The Conversational Language Understanding project to be called. | Yes |\n | deployment_name | string | The Conversational Language Understanding project deployment to be called. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Translator**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Translator resource. | Yes |\n | text | string | The input text. | Yes |\n | to | list[string] | The languages to translate the input text to. | Yes |\n | source_language | string | The language of the input text. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |"} -{"text_chunk": "Outputs\nIf the input parameter `parse_response` is set to `False` (default value), the raw API json output will be returned as a string. Refer to the REST API reference for details on API output. For Conversational Language Understanding, the output will be a list of raw API json responses, one response for each user utterance in the input. \n\nWhen `parse_response` is set to `True`, the tool will parse API output as follows:\n\n\n| Name | Type | Description |\n|-------------------------------------------------------------|--------|---------------------|\n| Abstractive Summarization | string | Abstractive summary. |\n| Extractive Summarization | list[string] | Extracted summary sentence strings. |\n| Conversation Summarization | string | Conversation summary based on `summary_aspect`. |\n| Entity Recognition | dict[string, string] | Recognized entities, where keys are entity names and values are entity categories. |\n| Key Phrase Extraction | list[string] | Extracted key phrases as strings. |\n| Language Detection | string | Detected language's ISO 639-1 code. |\n| PII Entity Recognition | string | Input `text` with PII entities redacted. |\n| Sentiment Analysis | string | Analyzed sentiment: `positive`, `neutral`, or `negative`. |\n| Conversational Language Understanding | list[dict[string, string]] | List of user utterances and associated intents. |\n| Translator | dict[string, string] | Translated text, where keys are the translated languages and values are the translated texts. |"} -{"text_chunk": "Flow YAML Schema\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe source JSON schema can be found at Flow.schema.json"} -{"text_chunk": "YAML syntax\n\n| Key | Type | Description |\n|----------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `$schema` | string | The YAML schema. If you use the prompt flow VS Code extension to author the YAML file, including `$schema` at the top of your file enables you to invoke schema and resource completions. |\n| `inputs` | object | Dictionary of flow inputs. The key is a name for the input within the context of the flow and the value is the flow input definition. |\n| `inputs.` | object | The flow input definition. See Flow input for the set of configurable properties. |\n| `outputs` | object | Dictionary of flow outputs. The key is a name for the output within the context of the flow and the value is the flow output definition. |\n| `outputs.` | object | The component output definition. See Flow output for the set of configurable properties. |\n| `nodes` | array | Sets of dictionary of individual nodes to run as steps within the flow. Node can use built-in tool or third-party tool. See Nodes for more information. |\n| `node_variants` | object | Dictionary of nodes with variants. The key is the node name and value contains variants definition and `default_variant_id`. See Node variants for more information. |\n| `environment` | object | The environment to use for the flow. The key can be `image` or `python_requirements_txt` and the value can be either a image or a python requirements text file. |\n| `additional_includes` | array | Additional includes is a list of files that can be shared among flows. Users can specify additional files and folders used by flow, and prompt flow will help copy them all to the snapshot during flow creation. |"} -{"text_chunk": "Flow input\n\n| Key | Type | Description | Allowed values |\n|-------------------|-------------------------------------------|------------------------------------------------------|-----------------------------------------------------|\n| `type` | string | The type of flow input. | `int`, `double`, `bool`, `string`, `list`, `object`, `image` |\n| `description` | string | Description of the input. | |\n| `default` | int, double, bool, string, list, object, image | The default value for the input. | |\n| `is_chat_input` | boolean | Whether the input is the chat flow input. | |\n| `is_chat_history` | boolean | Whether the input is the chat history for chat flow. | |"} -{"text_chunk": "Flow output\n\n| Key | Type | Description | Allowed values |\n|------------------|---------|-------------------------------------------------------------------------------|-----------------------------------------------------|\n| `type` | string | The type of flow output. | `int`, `double`, `bool`, `string`, `list`, `object` |\n| `description` | string | Description of the output. | |\n| `reference` | string | A reference to the node output, e.g. ${.output.} | |\n| `is_chat_output` | boolean | Whether the output is the chat flow output. | |"} -{"text_chunk": "Nodes\nNodes is a set of node which is a dictionary with following fields. Below, we only show the common fields of a single node using built-in tool.\n\n| Key | Type | Description | Allowed values |\n|----------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|\n| `name` | string | The name of the node. | |\n| `type` | string | The type of the node. | Type of built-in tool like `Python`, `Prompt`, `LLM` and third-party tool like `Vector Search`, etc. |\n| `inputs` | object | Dictionary of node inputs. The key is the input name and the value can be primitive value or a reference to the flow input or the node output, e.g. `${inputs.}`, `${.output}` or `${.output.}` | |\n| `source` | object | Dictionary of tool source used by the node. The key contains `type`, `path` and `tool`. The type can be `code`, `package` and `package_with_prompt`. | |\n| `provider` | string | It indicates the provider of the tool. Used when the `type` is LLM. | `AzureOpenAI` or `OpenAI` |\n| `connection` | string | The connection name which has been created before. Used when the `type` is LLM. | |\n| `api` | string | The api name of the provider. Used when the `type` is LLM. | |\n| `module` | string | The module name of the tool using by the node. Used when the `type` is LLM. | |\n| `use_variants` | bool | Whether the node has variants. | |"} -{"text_chunk": "Node variants\nNode variants is a dictionary containing variants definition for nodes with variants with their respective node names as dictionary keys.\nBelow, we explore the variants for a single node.\n\n| Key | Type | Description | Allowed values |\n|----------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|\n| `` | string | The name of the node. | |\n| `default_variant_id` | string | Default variant id. | |\n| `variants ` | object | This dictionary contains all node variations, with the variant id serving as the key and a node definition dictionary as the corresponding value. Within the node definition dictionary, the key labeled 'node' should contain a variant definition similar to Nodes, excluding the 'name' field. | |"} -{"text_chunk": "Examples\n\nFlow examples are available in the GitHub repository.\n\n- basic\n- web-classification\n- basic-chat\n- chat-with-pdf\n- eval-basic"} -{"text_chunk": "pf\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nManage prompt flow resources with the prompt flow CLI.\n\n| Command | Description |\n|---------------------------------|---------------------------------|\n| pf flow | Manage flows. |\n| pf connection | Manage connections. |\n| pf run | Manage runs. |\n| pf tool | Init or list tools. |\n| pf config | Manage config for current user. |"} -{"text_chunk": "pf flow\n\nManage promptflow flow flows.\n\n| Command | Description |\n| --- | --- |\n| pf flow init | Initialize a prompt flow directory. |\n| pf flow test | Test the prompt flow or flow node. |\n| pf flow validate | Validate a flow and generate `flow.tools.json` for it. |\n| pf flow build | Build a flow for further sharing or deployment. |\n| pf flow serve | Serve a flow as an endpoint. |"} -{"text_chunk": "pf flow init\n\nInitialize a prompt flow directory.\n\n```bash\npf flow init [--flow]\n [--entry]\n [--function]\n [--prompt-template]\n [--type]\n [--yes]\n```"} -{"text_chunk": "Examples\n\nCreate a flow folder with code, prompts and YAML specification of the flow.\n\n```bash\npf flow init --flow \n```\n\nCreate an evaluation prompt flow\n\n```bash\npf flow init --flow --type evaluation\n```\n\nCreate a flow in existing folder\n\n```bash\npf flow init --flow --entry --function --prompt-template \n```"} -{"text_chunk": "Optional Parameters\n\n`--flow`\n\nThe flow name to create.\n\n`--entry`\n\nThe entry file name.\n\n`--function`\n\nThe function name in entry file.\n\n`--prompt-template`\n\nThe prompt template parameter and assignment.\n\n`--type`\n\nThe initialized flow type. \naccepted value: standard, evaluation, chat\n\n`--yes --assume-yes -y`\n\nAutomatic yes to all prompts; assume 'yes' as answer to all prompts and run non-interactively."} -{"text_chunk": "pf flow test\n\nTest the prompt flow or flow node.\n\n```bash\npf flow test --flow\n [--inputs]\n [--node]\n [--variant]\n [--debug]\n [--interactive]\n [--verbose]\n```"} -{"text_chunk": "Examples\n\nTest the flow.\n\n```bash\npf flow test --flow \n```\n\nTest the flow with single line from input file.\n\n```bash\npf flow test --flow --inputs data_key1=data_val1 data_key2=data_val2\n```\n\nTest the flow with specified variant node.\n\n```bash\npf flow test --flow --variant '${node_name.variant_name}'\n```\n\nTest the single node in the flow.\n\n```bash\npf flow test --flow --node \n```\n\nDebug the single node in the flow.\n\n```bash\npf flow test --flow --node --debug\n```\n\nChat in the flow.\n\n```bash\npf flow test --flow --node --interactive\n```"} -{"text_chunk": "Required Parameter\n\n`--flow`\n\nThe flow directory to test."} -{"text_chunk": "Optional Parameters\n\n`--inputs`\n\nInput data for the flow. Example: --inputs data1=data1_val data2=data2_val\n\n`--node`\n\nThe node name in the flow need to be tested.\n\n`--variant`\n\nNode & variant name in format of ${node_name.variant_name}.\n\n`--debug`\n\nDebug the single node in the flow.\n\n`--interactive`\n\nStart a interactive chat session for chat flow.\n\n`--verbose`\n\nDisplays the output for each step in the chat flow."} -{"text_chunk": "pf flow validate\n\nValidate the prompt flow and generate a `flow.tools.json` under `.promptflow`. This file is required when using flow as a component in a Azure ML pipeline.\n\n```bash\npf flow validate --source\n [--debug]\n [--verbose]\n```"} -{"text_chunk": "Examples\n\nValidate the flow.\n\n```bash\npf flow validate --source \n```"} -{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow source to validate."} -{"text_chunk": "pf flow build\n\nBuild a flow for further sharing or deployment.\n\n```bash\npf flow build --source\n --output\n --format\n [--variant]\n [--verbose]\n [--debug]\n```"} -{"text_chunk": "Examples\n\nBuild a flow as docker, which can be built into Docker image via `docker build`.\n\n```bash\npf flow build --source --output --format docker\n```\n\nBuild a flow as docker with specific variant.\n\n```bash\npf flow build --source --output --format docker --variant '${node_name.variant_name}'\n```"} -{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow or run source to be used.\n\n`--output`\n\nThe folder to output built flow. Need to be empty or not existed.\n\n`--format`\n\nThe format to build flow into"} -{"text_chunk": "Optional Parameters\n\n`--variant`\n\nNode & variant name in format of ${node_name.variant_name}.\n\n`--verbose`\n\nShow more details for each step during build.\n\n`--debug`\n\nShow debug information during build."} -{"text_chunk": "pf flow serve\n\nServing a flow as an endpoint.\n\n```bash\npf flow serve --source\n [--port]\n [--host]\n [--environment-variables]\n [--verbose]\n [--debug]\n```"} -{"text_chunk": "Examples\n\nServe flow as an endpoint.\n\n```bash\npf flow serve --source \n```\n\nServe flow as an endpoint with specific port and host.\n\n```bash\npf flow serve --source --port --host --environment-variables key1=\"`${my_connection.api_key}`\" key2=\"value2\"\n```"} -{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow or run source to be used."} -{"text_chunk": "Optional Parameters\n\n`--port`\n\nThe port on which endpoint to run.\n\n`--host`\n\nThe host of endpoint.\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example: --environment-variable key1=\"\\`${my_connection.api_key}\\`\" key2=\"value2\". The value reference to connection keys will be resolved to the actual value, and all environment variables specified will be set into `os.environ`.\n\n`--verbose`\n\nShow more details for each step during serve.\n\n`--debug`\n\nShow debug information during serve."} -{"text_chunk": "pf connection\n\nManage prompt flow connections.\n\n| Command | Description |\n| --- | --- |\n| pf connection create | Create a connection. |\n| pf connection update | Update a connection. |\n| pf connection show | Show details of a connection. |\n| pf connection list | List all the connection. |\n| pf connection delete | Delete a connection. |"} -{"text_chunk": "pf connection create\n\nCreate a connection.\n\n```bash\npf connection create --file\n [--name]\n [--set]\n```"} -{"text_chunk": "Examples\n\nCreate a connection with YAML file.\n\n```bash\npf connection create -f \n```\n\nCreate a connection with YAML file with override.\n\n```bash\npf connection create -f --set api_key=\"\"\n```\n\nCreate a custom connection with .env file; note that overrides specified by `--set` will be ignored.\n\n```bash\npf connection create -f .env --name \n```"} -{"text_chunk": "Required Parameter\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow connection specification."} -{"text_chunk": "Optional Parameters\n\n`--name -n`\n\nName of the connection.\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} -{"text_chunk": "pf connection update\n\nUpdate a connection.\n\n```bash\npf connection update --name\n [--set]\n```"} -{"text_chunk": "Example\n\nUpdate a connection.\n\n```bash\npf connection update -n --set api_key=\"\"\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} -{"text_chunk": "Optional Parameter\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} -{"text_chunk": "pf connection show\n\nShow details of a connection.\n\n```bash\npf connection show --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} -{"text_chunk": "pf connection list\n\nList all the connection.\n\n```bash\npf connection list\n```"} -{"text_chunk": "pf connection delete\n\nDelete a connection.\n\n```bash\npf connection delete --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} -{"text_chunk": "pf run\n\nManage prompt flow runs.\n\n| Command | Description |\n| --- | --- |\n| pf run create | Create a run. |\n| pf run update | Update a run metadata, including display name, description and tags. |\n| pf run stream | Stream run logs to the console. |\n| pf run list | List runs. |\n| pf run show | Show details for a run. |\n| pf run show-details | Preview a run's intput(s) and output(s). |\n| pf run show-metrics | Print run metrics to the console. |\n| pf run visualize | Visualize a run. |\n| pf run archive | Archive a run. |\n| pf run restore | Restore an archived run. |"} -{"text_chunk": "pf run create\n\nCreate a run.\n\n```bash\npf run create [--file]\n [--flow]\n [--data]\n [--column-mapping]\n [--run]\n [--variant]\n [--stream]\n [--environment-variables]\n [--connections]\n [--set]\n [--source]\n```"} -{"text_chunk": "Examples\n\nCreate a run with YAML file.\n\n```bash\npf run create -f \n```\n\nCreate a run from flow directory and reference a run.\n\n```bash\npf run create --flow --data --column-mapping groundtruth='${data.answer}' prediction='${run.outputs.category}' --run --variant '${summarize_text_content.variant_0}' --stream\n```\n\nCreate a run from an existing run record folder.\n\n```bash\npf run create --source \n```"} -{"text_chunk": "Optional Parameters\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow run specification; can be overwritten by other parameters. Reference here for YAML schema.\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--data`\n\nLocal path to the data file.\n\n`--column-mapping`\n\nInputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns.\n\n`--run`\n\nReferenced flow run name. For example, you can run an evaluation flow against an existing run. For example, \"pf run create --flow evaluation_flow_dir --run existing_bulk_run\".\n\n`--variant`\n\nNode & variant name in format of `${node_name.variant_name}`.\n\n`--stream -s`\n\nIndicates whether to stream the run's logs to the console. \ndefault value: False\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example:\n`--environment-variable key1='${my_connection.api_key}' key2='value2'`. The value reference\nto connection keys will be resolved to the actual value, and all environment variables\nspecified will be set into os.environ.\n\n`--connections`\n\nOverwrite node level connections with provided value.\nExample: `--connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo`\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\nExample: `--set property1.property2=`.\n\n`--source`\n\nLocal path to the existing run record folder."} -{"text_chunk": "pf run update\n\nUpdate a run metadata, including display name, description and tags.\n\n```bash\npf run update --name\n [--set]\n```"} -{"text_chunk": "Example\n\nUpdate a run\n\n```bash\npf run update -n --set display_name=\"\" description=\"\" tags.key=\"value\"\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "Optional Parameter\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} -{"text_chunk": "pf run stream\n\nStream run logs to the console.\n\n```bash\npf run stream --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf run list\n\nList runs.\n\n```bash\npf run list [--all-results]\n [--archived-only]\n [--include-archived]\n [--max-results]\n```"} -{"text_chunk": "Optional Parameters\n\n`--all-results`\n\nReturns all results. \ndefault value: False\n\n`--archived-only`\n\nList archived runs only. \ndefault value: False\n\n`--include-archived`\n\nList archived runs and active runs. \ndefault value: False\n\n`--max-results -r`\n\nMax number of results to return. Default is 50. \ndefault value: 50"} -{"text_chunk": "pf run show\n\nShow details for a run.\n\n```bash\npf run show --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf run show-details\n\nPreview a run's input(s) and output(s).\n\n```bash\npf run show-details --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf run show-metrics\n\nPrint run metrics to the console.\n\n```bash\npf run show-metrics --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf run visualize\n\nVisualize a run in the browser.\n\n```bash\npf run visualize --names\n```"} -{"text_chunk": "Required Parameter\n\n`--names -n`\n\nName of the runs, comma separated."} -{"text_chunk": "pf run archive\n\nArchive a run.\n\n```bash\npf run archive --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf run restore\n\nRestore an archived run.\n\n```bash\npf run restore --name\n```"} -{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} -{"text_chunk": "pf tool\n\nManage promptflow tools.\n\n| Command | Description |\n| --- | --- |\n| pf tool init | Initialize a tool directory. |\n| pf tool list | List all tools in the environment. |\n| pf tool validate | Validate tools. |"} -{"text_chunk": "pf tool init\n\nInitialize a tool directory.\n\n```bash\npf tool init [--package]\n [--tool]\n [--set]\n```"} -{"text_chunk": "Examples\n\nCreating a package tool from scratch.\n\n```bash\npf tool init --package --tool \n```\n\nCreating a package tool with extra info.\n\n```bash\npf tool init --package --tool --set icon= category= tags=\"{'': ''}\"\n```\n\nCreating a package tool from scratch.\n\n```bash\npf tool init --package --tool \n```\n\nCreating a python tool from scratch.\n\n```bash\npf tool init --tool \n```"} -{"text_chunk": "Optional Parameters\n\n`--package`\n\nThe package name to create.\n\n`--tool`\n\nThe tool name to create.\n\n`--set`\n\nSet extra information about the tool, like category, icon and tags. Example: --set =."} -{"text_chunk": "pf tool list\n\nList all tools in the environment.\n\n```bash\npf tool list [--flow]\n```"} -{"text_chunk": "Examples\n\nList all package tool in the environment.\n\n```bash\npf tool list\n```\n\nList all package tool and code tool in the flow.\n\n```bash\npf tool list --flow \n```"} -{"text_chunk": "Optional Parameters\n\n`--flow`\n\nThe flow directory."} -{"text_chunk": "pf tool validate\n\nValidate tool.\n\n```bash\npf tool validate --source\n```"} -{"text_chunk": "Examples\n\nValidate single function tool.\n\n```bash\npf tool validate -\u2013source ..\n```\n\nValidate all tool in a package tool.\n\n```bash\npf tool validate -\u2013source \n```\n\nValidate tools in a python script.\n\n```bash\npf tool validate --source \n```"} -{"text_chunk": "Required Parameter\n\n`--source`\n\nThe tool source to be used."} -{"text_chunk": "pf config\n\nManage config for current user.\n\n| Command | Description |\n|-----------------------------------|--------------------------------------------|\n| pf config set | Set prompt flow configs for current user. |\n| pf config show | Show prompt flow configs for current user. |"} -{"text_chunk": "pf config set\n\nSet prompt flow configs for current user, configs will be stored at ~/.promptflow/pf.yaml.\n\n```bash\npf config set\n```"} -{"text_chunk": "Examples\n\nConfig connection provider to azure workspace for current user.\n\n```bash\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```"} -{"text_chunk": "pf config show\n\nShow prompt flow configs for current user.\n\n```bash\npf config show\n```"} -{"text_chunk": "Examples\n\nShow prompt flow for current user.\n\n```bash\npf config show\n```"} -{"text_chunk": "pfazure\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nManage prompt flow resources on Azure with the prompt flow CLI.\n\n| Command | Description |\n| --- | --- |\n| pfazure flow | Manage flows. |\n| pfazure run | Manage runs. |"} -{"text_chunk": "pfazure flow\n\nManage flows.\n\n| Command | Description |\n| --- | --- |\n| pfazure flow create | Create a flow. |\n| pfazure flow list | List flows in a workspace. |"} -{"text_chunk": "pfazure flow create\n\nCreate a flow in Azure AI from a local flow folder.\n\n```bash\npfazure flow create [--flow]\n [--set]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\n- `display_name`: Flow display name that will be created in remote. Default to be flow folder name + timestamp if not specified.\n- `type`: Flow type. Default to be \"standard\" if not specified. Available types are: \"standard\", \"evaluation\", \"chat\".\n- `description`: Flow description. e.g. \"--set description=\\.\"\n- `tags`: Flow tags. e.g. \"--set tags.key1=value1 tags.key2=value2.\"\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure flow list\n\nList remote flows on Azure AI.\n\n```bash\npfazure flow list [--max-results]\n [--include-others]\n [--type]\n [--output]\n [--archived-only]\n [--include-archived]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n [--output]\n```"} -{"text_chunk": "Parameters\n\n`--max-results -r`\n\nMax number of results to return. Default is 50, upper bound is 100.\n\n`--include-others`\n\nInclude flows created by other owners. By default only flows created by the current user are returned.\n\n`--type`\n\nFilter flows by type. Available types are: \"standard\", \"evaluation\", \"chat\".\n\n`--archived-only`\n\nList archived flows only.\n\n`--include-archived`\n\nList archived flows and active flows.\n\n`--output -o`\n\nOutput format. Allowed values: `json`, `table`. Default: `json`.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run\n\nManage prompt flow runs.\n\n| Command | Description |\n| --- | --- |\n| pfazure run create | Create a run. |\n| pfazure run list | List runs in a workspace. |\n| pfazure run show | Show details for a run. |\n| pfazure run stream | Stream run logs to the console. |\n| pfazure run show-details | Show a run details. |\n| pfazure run show-metrics | Show run metrics. |\n| pfazure run visualize | Visualize a run. |\n| pfazure run archive | Archive a run. |\n| pfazure run restore | Restore a run. |\n| pfazure run update | Update a run. |\n| pfazure run download | Download a run. |"} -{"text_chunk": "pfazure run create\n\nCreate a run.\n\n```bash\npfazure run create [--file]\n [--flow]\n [--data]\n [--column-mapping]\n [--run]\n [--variant]\n [--stream]\n [--environment-variables]\n [--connections]\n [--set]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow run specification; can be overwritten by other parameters. Reference here for YAML schema.\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--data`\n\nLocal path to the data file or remote data. e.g. azureml:name:version.\n\n`--column-mapping`\n\nInputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns.\n\n`--run`\n\nReferenced flow run name. For example, you can run an evaluation flow against an existing run. For example, \"pfazure run create --flow evaluation_flow_dir --run existing_bulk_run --column-mapping url='${data.url}'\".\n\n`--variant`\n\nNode & variant name in format of `${node_name.variant_name}`.\n\n`--stream -s`\n\nIndicates whether to stream the run's logs to the console. \ndefault value: False\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example:\n`--environment-variable key1='${my_connection.api_key}' key2='value2'`. The value reference\nto connection keys will be resolved to the actual value, and all environment variables\nspecified will be set into os.environ.\n\n`--connections`\n\nOverwrite node level connections with provided value.\nExample: `--connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo`\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\nExample: `--set property1.property2=`.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run list\n\nList runs in a workspace.\n\n```bash\npfazure run list [--archived-only]\n [--include-archived]\n [--max-results]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--archived-only`\n\nList archived runs only. \ndefault value: False\n\n`--include-archived`\n\nList archived runs and active runs. \ndefault value: False\n\n`--max-results -r`\n\nMax number of results to return. Default is 50, upper bound is 100. \ndefault value: 50\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run show\n\nShow details for a run.\n\n```bash\npfazure run show --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run stream\n\nStream run logs to the console.\n\n```bash\npfazure run stream --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run show-details\n\nShow a run details.\n\n```bash\npfazure run show-details --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run show-metrics\n\nShow run metrics.\n\n```bash\npfazure run show-metrics --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run visualize\n\nVisualize a run.\n\n```bash\npfazure run visualize --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run archive\n\nArchive a run.\n\n```bash\npfazure run archive --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run restore\n\nRestore a run.\n\n```bash\npfazure run restore --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run update\n\nUpdate a run's metadata, such as `display name`, `description` and `tags`.\n\n```bash\npfazure run update --name\n [--set display_name=\"\" description=\"\" tags.key=\"\"]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Examples\n\nSet `display name`, `description` and `tags`:\n\n```bash\npfazure run update --name --set display_name=\"\" description=\"\" tags.key=\"\"\n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--set`\n\nSet meta information of the run, like `display_name`, `description` or `tags`. Example: --set =.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "pfazure run download\n\nDownload a run's metadata, such as `input`, `output`, `snapshot` and `artifact`. After the download is finished, you can use `pf run create --source ` to register this run as a local run record, then you can use commands like `pf run show/visualize` to inspect the run just like a run that was created from local flow.\n\n```bash\npfazure run download --name\n [--output]\n [--overwrite]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} -{"text_chunk": "Examples\n\nDownload a run data to local:\n```bash\npfazure run download --name --output \n```"} -{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--output -o`\n\nOutput folder path to store the downloaded run data. Default to be `~/.promptflow/.runs` if not specified\n\n`--overwrite`\n\nOverwrite the existing run data if the output folder already exists. Default to be `False` if not specified\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} -{"text_chunk": "PLACEHOLDER"} -{"text_chunk": "Run YAML Schema\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe source JSON schema can be found at Run.schema.json"} -{"text_chunk": "YAML syntax\n\n| Key | Type | Description |\n|-------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `$schema` | string | The YAML schema. If you use the prompt flow VS Code extension to author the YAML file, including $schema at the top of your file enables you to invoke schema and resource completions. |\n| `name` | string | The name of the run. |\n| `flow` | string | Path of the flow directory. |\n| `description` | string | Description of the run. |\n| `display_name` | string | Display name of the run. |\n| `runtime` | string | The runtime for the run. Only supported for cloud run. |\n| `data` | string | Input data for the run. Local path or remote uri(starts with azureml: or public URL) are supported. Note: remote uri is only supported for cloud run. |\n| `run` | string | Referenced flow run name. For example, you can run an evaluation flow against an existing run. |\n| `column_mapping` | object | Inputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns. |\n| `connections` | object | Overwrite node level connections with provided value. Example: --connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo |\n| `environment_variables` | object/string | Environment variables to set by specifying a property path and value. Example: `{\"key1\"=\"${my_connection.api_key}\"}`. The value reference to connection keys will be resolved to the actual value, and all environment variables specified will be set into os.environ. |\n| `properties` | object | Dictionary of properties of the run. |\n| `tags` | object | Dictionary of tags of the run. |\n| `resources` | object | Dictionary of resources used for automatic runtime. Only supported for cloud run. See Resources Schema for the set of configurable properties. |\n| `variant` | string | The variant for the run. |\n| `status` | string | The status of the run. Only available for when getting an existing run. Won't take affect if set when creating a run. |"} -{"text_chunk": "Resources Schema\n\n| Key | Type | Description |\n|-------------------------------------|---------|-------------------------------------------------------------|\n| `instance_type` | string | The instance type for automatic runtime of the run. |\n| `idle_time_before_shutdown_minutes` | integer | The idle time before automatic runtime shutdown in minutes. |"} -{"text_chunk": "Examples\n\nRun examples are available in the GitHub repository.\n\n- basic\n- web-classification\n- flow-with-additional-includes"} -{"text_chunk": "Azure OpenAI GPT-4 Turbo with Vision"} -{"text_chunk": "Introduction\nAzure OpenAI GPT-4 Turbo with Vision tool enables you to leverage your AzureOpenAI GPT-4 Turbo with Vision model deployment to analyze images and provide textual responses to questions about them."} -{"text_chunk": "Prerequisites\n\n- Create AzureOpenAI resources\n\n Create Azure OpenAI resources with instruction\n\n- Create a GPT-4 Turbo with Vision deployment\n\n Browse to Azure OpenAI Studio and sign in with the credentials associated with your Azure OpenAI resource. During or after the sign-in workflow, select the appropriate directory, Azure subscription, and Azure OpenAI resource.\n\n Under Management select Deployments and Create a GPT-4 Turbo with Vision deployment by selecting model name: `gpt-4` and model version `vision-preview`."} -{"text_chunk": "Connection\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| AzureOpenAI | Required | Required | Required | Required |"} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| connection | AzureOpenAI | the AzureOpenAI connection to be used in the tool | Yes |\n| deployment\\_name | string | the language model to use | Yes |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is 512. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |"} -{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| string | The text of one response of conversation |"} -{"text_chunk": "Content Safety (Text)\n\nAzure Content Safety is a content moderation service developed by Microsoft that help users detect harmful content from different modalities and languages. This tool is a wrapper for the Azure Content Safety Text API, which allows you to detect text content and get moderation results. See the Azure Content Safety for more information."} -{"text_chunk": "Requirements\n\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users,\n `pip install promptflow-tools`\n> [!NOTE]\n> Content Safety (Text) tool is now incorporated into the latest `promptflow-tools` package. If you have previously installed the package `promptflow-contentsafety`, please uninstall it to avoid the duplication in your local tool list."} -{"text_chunk": "Prerequisites\n\n- Create an Azure Content Safety resource.\n- Add \"Azure Content Safety\" connection in prompt flow. Fill \"API key\" field with \"Primary key\" from \"Keys and Endpoint\" section of created resource."} -{"text_chunk": "Inputs\n\nYou can use the following parameters as inputs for this tool:\n\n| Name | Type | Description | Required |\n| ---- | ---- | ----------- | -------- |\n| text | string | The text that need to be moderated. | Yes |\n| hate_category | string | The moderation sensitivity for Hate category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for hate category. The other three options mean different degrees of strictness in filtering out hate content. The default option is *medium_sensitivity*. | Yes |\n| sexual_category | string | The moderation sensitivity for Sexual category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for sexual category. The other three options mean different degrees of strictness in filtering out sexual content. The default option is *medium_sensitivity*. | Yes |\n| self_harm_category | string | The moderation sensitivity for Self-harm category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for self-harm category. The other three options mean different degrees of strictness in filtering out self_harm content. The default option is *medium_sensitivity*. | Yes |\n| violence_category | string | The moderation sensitivity for Violence category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for violence category. The other three options mean different degrees of strictness in filtering out violence content. The default option is *medium_sensitivity*. | Yes |\n\nFor more information, please refer to Azure Content Safety"} -{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool:\n\n\n Output\n \n```json\n{\n \"action_by_category\": {\n \"Hate\": \"Accept\",\n \"SelfHarm\": \"Accept\",\n \"Sexual\": \"Accept\",\n \"Violence\": \"Accept\"\n },\n \"suggested_action\": \"Accept\"\n }\n```\n\n\n\nThe `action_by_category` field gives you a binary value for each category: *Accept* or *Reject*. This value shows if the text meets the sensitivity level that you set in the request parameters for that category.\n\nThe `suggested_action` field gives you an overall recommendation based on the four categories. If any category has a *Reject* value, the `suggested_action` will be *Reject* as well."} -{"text_chunk": "Embedding"} -{"text_chunk": "Introduction\nOpenAI's embedding models convert text into dense vector representations for various NLP tasks. See the OpenAI Embeddings API for more information."} -{"text_chunk": "Prerequisite\nCreate OpenAI resources:\n\n- **OpenAI**\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- **Azure OpenAI (AOAI)**\n\n Create Azure OpenAI resources with instruction"} -{"text_chunk": "**Connections**\n\nSetup connections to provide resources in embedding tool.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| OpenAI | Required | Required | - | - |\n| AzureOpenAI | Required | Required | Required | Required |"} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|-----------------------------------------------------------------------|----------|\n| input | string | the input text to embed | Yes |\n| connection | string | the connection for the embedding tool use to provide resources | Yes |\n| model/deployment_name | string | instance of the text-embedding engine to use. Fill in model name if you use OpenAI connection, or deployment name if use Azure OpenAI connection. | Yes |"} -{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| list | The vector representations for inputs |\n\nThe following is an example response returned by the embedding tool:\n\n\n Output\n \n```\n[-0.005744616035372019,\n-0.007096089422702789,\n-0.00563855143263936,\n-0.005272455979138613,\n-0.02355326898396015,\n0.03955197334289551,\n-0.014260607771575451,\n-0.011810848489403725,\n-0.023170066997408867,\n-0.014739611186087132,\n...]\n```"} -{"text_chunk": "Faiss Index Lookup\n\nFaiss Index Lookup is a tool tailored for querying within a user-provided Faiss-based vector store. In combination with our Large Language Model (LLM) tool, it empowers users to extract contextually relevant information from a domain knowledge base."} -{"text_chunk": "Requirements\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users, if your index is stored in local path,\n \n `pip install promptflow-vectordb`\n \n if your index is stored in Azure storage,\n\n `pip install promptflow-vectordb[azure]`"} -{"text_chunk": "Prerequisites\n - step 1. Prepare an accessible path on Azure Blob Storage. Here's the guide if a new storage account needs to be created: Azure Storage Account.\n - step 2. Create related Faiss-based index files on Azure Blob Storage. We support the LangChain format (index.faiss + index.pkl) for the index files, which can be prepared either by employing our promptflow-vectordb SDK or following the quick guide from LangChain documentation. Please refer to the instructions of An example code for creating Faiss index for building index using promptflow-vectordb SDK.\n - step 3. Based on where you put your own index files, the identity used by the promptflow runtime should be granted with certain roles. Please refer to Steps to assign an Azure role:\n\n | Location | Role |\n | ---- | ---- |\n | workspace datastores or workspace default blob | AzureML Data Scientist |\n | other blobs | Storage Blob Data Reader |"} -{"text_chunk": "For local users,\n - Create Faiss-based index files in local path by only doing step 2 above."} -{"text_chunk": "Inputs\n\nThe tool accepts the following inputs:\n\n| Name | Type | Description | Required |\n| ---- | ---- | ----------- | -------- |\n| path | string | URL or path for the vector store.local path (for local users):`` Azure blob URL format (with [azure] extra installed):https://``.blob.core.windows.net/``/``.AML datastore URL format (with [azure] extra installed):azureml://subscriptions/``/resourcegroups/``/workspaces/``/data/``public http/https URL (for public demonstration):http(s)://`` | Yes |\n| vector | list[float] | The target vector to be queried, which can be generated by the LLM tool. | Yes |\n| top_k | integer | The count of top-scored entities to return. Default value is 3. | No |"} -{"text_chunk": "Outputs\n\nThe following is an example for JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by our promptflow-vectordb SDK. For the Faiss Index Search, the following fields are populated:\n\n| Field Name | Type | Description |\n| ---- | ---- | ----------- |\n| text | string | Text of the entity |\n| score | float | Distance between the entity and the query vector |\n| metadata | dict | Customized key-value pairs provided by user when create the index |\n\n\n Output\n \n```json\n[\n {\n \"metadata\": {\n \"link\": \"http://sample_link_0\",\n \"title\": \"title0\"\n },\n \"original_entity\": null,\n \"score\": 0,\n \"text\": \"sample text #0\",\n \"vector\": null\n },\n {\n \"metadata\": {\n \"link\": \"http://sample_link_1\",\n \"title\": \"title1\"\n },\n \"original_entity\": null,\n \"score\": 0.05000000447034836,\n \"text\": \"sample text #1\",\n \"vector\": null\n },\n {\n \"metadata\": {\n \"link\": \"http://sample_link_2\",\n \"title\": \"title2\"\n },\n \"original_entity\": null,\n \"score\": 0.20000001788139343,\n \"text\": \"sample text #2\",\n \"vector\": null\n }\n]\n\n```"} -{"text_chunk": "LLM"} -{"text_chunk": "Introduction\nPrompt flow LLM tool enables you to leverage widely used large language models like OpenAI or Azure OpenAI (AOAI) for natural language processing. \n\nPrompt flow provides a few different LLM APIs:\n- **Completion**: OpenAI's completion models generate text based on provided prompts.\n- **Chat**: OpenAI's chat models facilitate interactive conversations with text-based inputs and responses.\n> [!NOTE]\n> We now remove the `embedding` option from LLM tool api setting. You can use embedding api with Embedding tool."} -{"text_chunk": "Prerequisite\nCreate OpenAI resources:\n\n- **OpenAI**\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- **Azure OpenAI (AOAI)**\n\n Create Azure OpenAI resources with instruction"} -{"text_chunk": "**Connections**\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| OpenAI | Required | Required | - | - |\n| AzureOpenAI | Required | Required | Required | Required |"} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|-----------------------------------------------------------------------------------------|----------|\n| prompt | string | text prompt that the language model will complete | Yes |\n| model, deployment_name | string | the language model to use | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the completion. Default is 16. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| suffix | string | text appended to the end of the completion | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| logprobs | integer | the number of log probabilities to generate. Default is null. | No |\n| echo | boolean | value that indicates whether to echo back the prompt in the response. Default is false. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |\n| best\\_of | integer | the number of best completions to generate. Default is 1. | No |\n| logit\\_bias | dictionary | the logit bias for the language model. Default is empty dictionary. | No |"} -{"text_chunk": "Chat\n\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| prompt | string | text prompt that the language model will response | Yes |\n| model, deployment_name | string | the language model to use | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is inf. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0.| No |\n| logit\\_bias | dictionary | the logit bias for the language model. Default is empty dictionary. | No |\n| function\\_call | object | value that controls which function is called by the model. Default is null. | No |\n| functions | list | a list of functions the model may generate JSON inputs for. Default is null. | No |\n| response_format | object | an object specifying the format that the model must output. Default is null. | No |"} -{"text_chunk": "Outputs\n\n| API | Return Type | Description |\n|------------|-------------|------------------------------------------|\n| Completion | string | The text of one predicted completion |\n| Chat | string | The text of one response of conversation |"} -{"text_chunk": "How to use LLM Tool?\n\n1. Setup and select the connections to OpenAI resources\n2. Configure LLM model api and its parameters\n3. Prepare the Prompt with guidance."} -{"text_chunk": "Open Model LLM"} -{"text_chunk": "Introduction\n\nThe Open Model LLM tool enables the utilization of a variety of Open Model and Foundational Models, such as Falcon and Llama 2, for natural language processing in Azure ML Prompt Flow.\n\nHere's how it looks in action on the Visual Studio Code prompt flow extension. In this example, the tool is being used to call a LlaMa-2 chat endpoint and asking \"What is CI?\".\n\n!Screenshot of the Open Model LLM On VScode Prompt Flow extension\n\nThis prompt flow tool supports two different LLM API types:\n\n- **Chat**: Shown in the example above. The chat API type facilitates interactive conversations with text-based inputs and responses.\n- **Completion**: The Completion API type is used to generate single response text completions based on provided prompt input."} -{"text_chunk": "Quick Overview: How do I use Open Model LLM Tool?\n\n1. Choose a Model from the AzureML Model Catalog and get it deployed.\n2. Connect to the model deployment.\n3. Configure the open model llm tool settings.\n4. Prepare the Prompt with guidance.\n5. Run the flow."} -{"text_chunk": "Prerequisites: Model Deployment\n\n1. Pick the model which matched your scenario from the Azure Machine Learning model catalog.\n2. Use the \"Deploy\" button to deploy the model to a AzureML Online Inference endpoint.\n2.1. Use one of the Pay as you go deployment options.\n\nMore detailed instructions can be found here Deploying foundation models to endpoints for inferencing."} -{"text_chunk": "Prerequisites: Connect to the Model\n\nIn order for prompt flow to use your deployed model, you will need to connect to it. There are several ways to connect."} -{"text_chunk": "1. Endpoint Connections\n\nOnce associated to a AzureML or Azure AI Studio workspace, the Open Model LLM tool can use the endpoints on that workspace.\n\n1. **Using AzureML or Azure AI Studio workspaces**: If you are using prompt flow in one of the web page based browsers workspaces, the online endpoints available on that workspace will automatically who up.\n\n2. **Using VScode or Code First**: If you are using prompt flow in VScode or one of the Code First offerings, you will need to connect to the workspace. The Open Model LLM tool uses the azure.identity DefaultAzureCredential client for authorization. One way is through setting environment credential values."} -{"text_chunk": "2. Custom Connections\n\nThe Open Model LLM tool uses the CustomConnection. Prompt flow supports two types of connections:\n\n1. **Workspace Connections** - These are connections which are stored as secrets on an Azure Machine Learning workspace. While these can be used, in many places, the are commonly created and maintained in the Studio UI.\n\n2. **Local Connections** - These are connections which are stored locally on your machine. These connections are not available in the Studio UX's, but can be used with the VScode extension.\n\nInstructions on how to create a workspace or local Custom Connection can be found here.\n\nThe required keys to set are:\n\n1. **endpoint_url**\n - This value can be found at the previously created Inferencing endpoint.\n2. **endpoint_api_key**\n - Ensure to set this as a secret value.\n - This value can be found at the previously created Inferencing endpoint.\n3. **model_family**\n - Supported values: LLAMA, DOLLY, GPT2, or FALCON\n - This value is dependent on the type of deployment you are targeting."} -{"text_chunk": "Running the Tool: Inputs\n\nThe Open Model LLM tool has a number of parameters, some of which are required. Please see the below table for details, you can match these to the screen shot above for visual clarity.\n\n| Name | Type | Description | Required |\n|------|------|-------------|----------|\n| api | string | This is the API mode and will depend on the model used and the scenario selected. *Supported values: (Completion \\| Chat)* | Yes |\n| endpoint_name | string | Name of an Online Inferencing Endpoint with a supported model deployed on it. Takes priority over connection. | No |\n| temperature | float | The randomness of the generated text. Default is 1. | No |\n| max_new_tokens | integer | The maximum number of tokens to generate in the completion. Default is 500. | No |\n| top_p | float | The probability of using the top choice from the generated tokens. Default is 1. | No |\n| model_kwargs | dictionary | This input is used to provide configuration specific to the model used. For example, the Llama-02 model may use {\\\"temperature\\\":0.4}. *Default: {}* | No |\n| deployment_name | string | The name of the deployment to target on the Online Inferencing endpoint. If no value is passed, the Inferencing load balancer traffic settings will be used. | No |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |"} -{"text_chunk": "Outputs\n\n| API | Return Type | Description |\n|------------|-------------|------------------------------------------|\n| Completion | string | The text of one predicted completion |\n| Chat | string | The text of one response int the conversation |"} -{"text_chunk": "Deploying to an Online Endpoint\n\nWhen deploying a flow containing the Open Model LLM tool to an online endpoint, there is an additional step to setup permissions. During deployment through the web pages, there is a choice between System-assigned and User-assigned Identity types. Either way, using the Azure Portal (or a similar functionality), add the \"Reader\" Job function role to the identity on the Azure Machine Learning workspace or Ai Studio project which is hosting the endpoint. The prompt flow deployment may need to be refreshed."} -{"text_chunk": "OpenAI GPT-4V"} -{"text_chunk": "Introduction\nOpenAI GPT-4V tool enables you to leverage OpenAI's GPT-4 with vision, also referred to as GPT-4V or gpt-4-vision-preview in the API, to take images as input and answer questions about them."} -{"text_chunk": "Prerequisites\n\n- Create OpenAI resources\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- Get Access to GPT-4 API\n\n To use GPT-4 with vision, you need access to GPT-4 API. Learn more about How to get access to GPT-4 API"} -{"text_chunk": "Connection\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY |\n|-------------|----------|----------|\n| OpenAI | Required | Required |"} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| connection | OpenAI | the OpenAI connection to be used in the tool | Yes |\n| model | string | the language model to use, currently only support gpt-4-vision-preview | Yes |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is 512. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |"} -{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| string | The text of one response of conversation |"} -{"text_chunk": "Prompt"} -{"text_chunk": "Introduction\nThe Prompt Tool in PromptFlow offers a collection of textual templates that serve as a starting point for creating prompts. \nThese templates, based on the Jinja2 template engine, facilitate the definition of prompts. The tool proves useful \nwhen prompt tuning is required prior to feeding the prompts into the Language Model (LLM) model in PromptFlow."} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|--------------------|--------|----------------------------------------------------------|----------|\n| prompt | string | The prompt template in Jinja | Yes |\n| Inputs | - | List of variables of prompt template and its assignments | - |"} -{"text_chunk": "Outputs\n\nThe prompt text parsed from the prompt + Inputs"} -{"text_chunk": "How to write Prompt?\n\n1. Prepare jinja template. Learn more about Jinja\n\n_In below example, the prompt incorporates Jinja templating syntax to dynamically generate the welcome message and personalize it based on the user's name. It also presents a menu of options for the user to choose from. Depending on whether the user_name variable is provided, it either addresses the user by name or uses a generic greeting._\n\n```jinja\nWelcome to {{ website_name }}!\n{% if user_name %}\n Hello, {{ user_name }}!\n{% else %}\n Hello there!\n{% endif %}\nPlease select an option from the menu below:\n1. View your account\n2. Update personal information\n3. Browse available products\n4. Contact customer support\n```\n\n2. Assign value for the variables.\n\n_In above example, two variables would be automatically detected and listed in '**Inputs**' section. Please assign values._"} -{"text_chunk": "Sample 1\nInputs\n\n| Variable | Type | Sample Value | \n|---------------|--------|--------------|\n| website_name | string | \"Microsoft\" |\n| user_name | string | \"Jane\" |\n\nOutputs\n\n```\nWelcome to Microsoft! Hello, Jane! Please select an option from the menu below: 1. View your account 2. Update personal information 3. Browse available products 4. Contact customer support\n```"} -{"text_chunk": "Sample 2\n\nInputs\n\n| Variable | Type | Sample Value | \n|--------------|--------|----------------|\n| website_name | string | \"Bing\" |\n| user_name | string | \" |\n\nOutputs\n\n```\nWelcome to Bing! Hello there! Please select an option from the menu below: 1. View your account 2. Update personal information 3. Browse available products 4. Contact customer support\n```"} -{"text_chunk": "Python"} -{"text_chunk": "Introduction\nUsers are empowered by the Python Tool to offer customized code snippets as self-contained executable nodes in PromptFlow.\nUsers can effortlessly create Python tools, edit code, and verify results with ease."} -{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|--------|--------|------------------------------------------------------|---------|\n| Code | string | Python code snippet | Yes |\n| Inputs | - | List of tool function parameters and its assignments | - |"} -{"text_chunk": "Types\n\n| Type | Python example | Description |\n|-----------------------------------------------------|---------------------------------|--------------------------------------------|\n| int | param: int | Integer type |\n| bool | param: bool | Boolean type |\n| string | param: str | String type |\n| double | param: float | Double type |\n| list | param: list or param: List[T] | List type |\n| object | param: dict or param: Dict[K, V] | Object type |\n| Connection | param: CustomConnection | Connection type, will be handled specially |\n\n\nParameters with `Connection` type annotation will be treated as connection inputs, which means:\n- Promptflow extension will show a selector to select the connection.\n- During execution time, promptflow will try to find the connection with the name same from parameter value passed in.\n\nNote that `Union[...]` type annotation is supported **ONLY** for connection type,\nfor example, `param: Union[CustomConnection, OpenAIConnection]`."} -{"text_chunk": "Outputs\n\nThe return of the python tool function."} -{"text_chunk": "How to write Python Tool?"} -{"text_chunk": "Guidelines\n\n1. Python Tool Code should consist of a complete Python code, including any necessary module imports.\n\n2. Python Tool Code must contain a function decorated with @tool (tool function), serving as the entry point for execution. The @tool decorator should be applied only once within the snippet.\n\n _Below sample defines python tool \"my_python_tool\", decorated with @tool_\n\n3. Python tool function parameters must be assigned in 'Inputs' section\n\n _Below sample defines inputs \"message\" and assign with \"world\"_\n\n4. Python tool function shall have return\n\n _Below sample returns a concatenated string_"} -{"text_chunk": "Code\n\nThe snippet below shows the basic structure of a tool function. Promptflow will read the function and extract inputs\nfrom function parameters and type annotations.\n\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection"} -{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(message: str, my_conn: CustomConnection) -> str:\n my_conn_dict = dict(my_conn)\n # Do some function call with my_conn_dict...\n return 'hello ' + message\n```"} -{"text_chunk": "Inputs\n\n| Name | Type | Sample Value in Flow Yaml | Value passed to function|\n|---------|--------|-------------------------| ------------------------|\n| message | string | \"world\" | \"world\" |\n| my_conn | CustomConnection | \"my_conn\" | CustomConnection object |\n\nPromptflow will try to find the connection named 'my_conn' during execution time."} -{"text_chunk": "outputs\n\n```python\n\"hello world\"\n```"} -{"text_chunk": "Keyword Arguments Support\nStarting from version 1.0.0 of PromptFlow and version 1.4.0 of Prompt flow for VS Code,\nwe have introduced support for keyword arguments (kwargs) in the Python tool.\n\n\n```python\nfrom promptflow import tool\n\n\n@tool\ndef print_test(normal_input: str, **kwargs):\n for key, value in kwargs.items():\n print(f\"Key {key}'s value is {value}\")\n return len(kwargs)\n\n```\nWhen you add `kwargs` in your python tool like above code, you can insert variable number of inputs by the `+Add input` button.\n\n!Screenshot of the kwargs On VScode Prompt Flow extension"} -{"text_chunk": "SerpAPI"} -{"text_chunk": "Introduction\n\nThe SerpAPI API is a Python tool that provides a wrapper to the SerpAPI Google Search Engine Results API and [SerpApi Bing Search Engine Results API\n](https://serpapi.com/bing-search-api). \nWe could use the tool to retrieve search results from a number of different search engines, including Google and Bing, and you can specify a range of search parameters, such as the search query, location, device type, and more."} -{"text_chunk": "Prerequisite\n\nSign up at SERP API homepage"} -{"text_chunk": "Connection\nConnection is the model used to establish connections with Serp API.\n\n| Type | Name | API KEY |\n|-------------|----------|----------|\n| Serp | Required | Required |\n\n_**API Key** is on SerpAPI account dashboard_"} -{"text_chunk": "Inputs\n\nThe **serp api** tool supports following parameters:\n\n\n| Name | Type | Description | Required |\n|----------|---------|---------------------------------------------------------------|----------|\n| query | string | The search query to be executed. | Yes |\n| engine | string | The search engine to use for the search. Default is 'google'. | Yes |\n| num | integer | The number of search results to return.Default is 10. | No |\n| location | string | The geographic location to execute the search from. | No |\n| safe | string | The safe search mode to use for the search. Default is 'off'. | No |"} -{"text_chunk": "Outputs\nThe json representation from serpapi query.\n\n| Engine | Return Type | Output |\n|----------|-------------|-------------------------------------------------------|\n| google | json | Sample |\n| bing | json | Sample |"} -{"text_chunk": "Vector DB Lookup\n\nVector DB Lookup is a vector search tool that allows users to search top k similar vectors from vector database. This tool is a wrapper for multiple third-party vector databases. The list of current supported databases is as follows.\n\n| Name | Description |\n| --- | --- |\n| Azure Cognitive Search | Microsoft's cloud search service with built-in AI capabilities that enrich all types of information to help identify and explore relevant content at scale. |\n| Qdrant | Qdrant is a vector similarity search engine that provides a production-ready service with a convenient API to store, search and manage points (i.e. vectors) with an additional payload. |\n| Weaviate | Weaviate is an open source vector database that stores both objects and vectors. This allows for combining vector search with structured filtering. |\n\nThis tool will support more vector databases."} -{"text_chunk": "Requirements\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users,\n\n `pip install promptflow-vectordb`"} -{"text_chunk": "Prerequisites\n\nThe tool searches data from a third-party vector database. To use it, you should create resources in advance and establish connection between the tool and the resource.\n\n - **Azure Cognitive Search:**\n - Create resource Azure Cognitive Search.\n - Add \"Cognitive search\" connection. Fill \"API key\" field with \"Primary admin key\" from \"Keys\" section of created resource, and fill \"API base\" field with the URL, the URL format is `https://{your_serive_name}.search.windows.net`.\n\n - **Qdrant:**\n - Follow the installation to deploy Qdrant to a self-maintained cloud server.\n - Add \"Qdrant\" connection. Fill \"API base\" with your self-maintained cloud server address and fill \"API key\" field.\n\n - **Weaviate:**\n - Follow the installation to deploy Weaviate to a self-maintained instance.\n - Add \"Weaviate\" connection. Fill \"API base\" with your self-maintained instance address and fill \"API key\" field."} -{"text_chunk": "Inputs\n\nThe tool accepts the following inputs:\n- **Azure Cognitive Search:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | CognitiveSearchConnection | The created connection for accessing to Cognitive Search endpoint. | Yes |\n | index_name | string | The index name created in Cognitive Search resource. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | vector_field | string | The vector field name. The target vector is searched in this vector field. | Yes |\n | search_params | dict | The search parameters. It's key-value pairs. Except for parameters in the tool input list mentioned above, additional search parameters can be formed into a JSON object as search_params. For example, use `{\"select\": \"\"}` as search_params to select the returned fields, use `{\"search\": \"\"}` to perform a hybrid search. | No |\n | search_filters | dict | The search filters. It's key-value pairs, the input format is like `{\"filter\": \"\"}` | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |\n\n- **Qdrant:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | QdrantConnection | The created connection for accessing to Qdrant server. | Yes |\n | collection_name | string | The collection name created in self-maintained cloud server. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | search_params | dict | The search parameters can be formed into a JSON object as search_params. For example, use `{\"params\": {\"hnsw_ef\": 0, \"exact\": false, \"quantization\": null}}` to set search_params. | No |\n | search_filters | dict | The search filters. It's key-value pairs, the input format is like `{\"filter\": {\"should\": [{\"key\": \"\", \"match\": {\"value\": \"\"}}]}}` | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |\n\n- **Weaviate:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | WeaviateConnection | The created connection for accessing to Weaviate. | Yes |\n | class_name | string | The class name. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |"} -{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by promptflow-vectordb SDK. \n- **Azure Cognitive Search:**\n\n For Azure Cognitive Search, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | @search.score from the original entity, which evaluates the similarity between the entity and the query vector |\n | text | string | text of the entity|\n | vector | list | vector of the entity|\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"@search.score\": 0.5099789,\n \"id\": \"\",\n \"your_text_filed_name\": \"sample text1\",\n \"your_vector_filed_name\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972],\n \"your_additional_field_name\": \"\"\n },\n \"score\": 0.5099789,\n \"text\": \"sample text1\",\n \"vector\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972]\n }\n ]\n ```\n \n\n- **Qdrant:**\n\n For Qdrant, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | metadata | dict | payload from the original entity|\n | score | float | score from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text of the payload|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": {\n \"text\": \"sample text1\"\n },\n \"original_entity\": {\n \"id\": 1,\n \"payload\": {\n \"text\": \"sample text1\"\n },\n \"score\": 1,\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673],\n \"version\": 0\n },\n \"score\": 1,\n \"text\": \"sample text1\",\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673]\n }\n ]\n ```\n \n\n- **Weaviate:**\n\n For Weaviate, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | certainty from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text in the original entity|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"_additional\": {\n \"certainty\": 1,\n \"distance\": 0,\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n },\n \"text\": \"sample text1.\"\n },\n \"score\": 1,\n \"text\": \"sample text1.\",\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n }\n ]\n ```"} -{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by promptflow-vectordb SDK. \n- **Azure Cognitive Search:**\n\n For Azure Cognitive Search, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | @search.score from the original entity, which evaluates the similarity between the entity and the query vector |\n | text | string | text of the entity|\n | vector | list | vector of the entity|\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"@search.score\": 0.5099789,\n \"id\": \"\",\n \"your_text_filed_name\": \"sample text1\",\n \"your_vector_filed_name\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972],\n \"your_additional_field_name\": \"\"\n },\n \"score\": 0.5099789,\n \"text\": \"sample text1\",\n \"vector\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972]\n }\n ]\n ```\n \n\n- **Qdrant:**\n\n For Qdrant, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | metadata | dict | payload from the original entity|\n | score | float | score from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text of the payload|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": {\n \"text\": \"sample text1\"\n },\n \"original_entity\": {\n \"id\": 1,\n \"payload\": {\n \"text\": \"sample text1\"\n },\n \"score\": 1,\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673],\n \"version\": 0\n },\n \"score\": 1,\n \"text\": \"sample text1\",\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673]\n }\n ]\n ```\n \n\n- **Weaviate:**\n\n For Weaviate, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | certainty from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text in the original entity|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"_additional\": {\n \"certainty\": 1,\n \"distance\": 0,\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n },\n \"text\": \"sample text1.\"\n },\n \"score\": 1,\n \"text\": \"sample text1.\",\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n }\n ]\n ```"} From 9bf15a11305c98e2e6cc207dfaaf596c6aba0241 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 11:42:35 +0800 Subject: [PATCH 026/112] add documents nodes file --- .../test_data_gen/document-nodes-test.jsonl | 293 ++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 examples/test_data_gen/document-nodes-test.jsonl diff --git a/examples/test_data_gen/document-nodes-test.jsonl b/examples/test_data_gen/document-nodes-test.jsonl new file mode 100644 index 00000000000..7413d5935d3 --- /dev/null +++ b/examples/test_data_gen/document-nodes-test.jsonl @@ -0,0 +1,293 @@ +{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow.", "document_node": "{\"id_\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b402c5d-538d-408b-9cb1-d66d47fffa40\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a51a60cd4ae560e102258e62ad38f93648f1d46243cb797a66704c23cd9ab80a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"text\": \"Add conditional control to a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\\n\\nThis guide will help you learn how to use activate config to add conditional control to your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`.", "document_node": "{\"id_\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15868ad6-c777-44b2-8e97-9be423ee1483\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ad88a6a9078f088ce0a7ed654c73052d2178573eb746ac2c4162ef58f96634e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"text\": \"Prerequisites\\n\\nPlease ensure that your promptflow version is greater than `0.1.0b5`.\", \"start_char_idx\": 2, \"end_char_idx\": 86, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::", "document_node": "{\"id_\": \"31293458-8cee-4967-8348-4114666ad247\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"77279509-65c8-4fa1-9ced-eff19c2bd279\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"85d4f1ef1cd02a2a25836c3e629e10e19b777a402ee672b9021ae20a3cd5627d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"text\": \"Usage\\n\\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\\n\\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\\n\\n::::{tab-set}\\n:::{tab-item} YAML\\n:sync: YAML\\n\\nYou can add activate config in the node section of flow yaml.\\n```yaml\\nactivate:\\n when: ${node.output}\\n is: true\\n```\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\\n!visual_editor\\n\\n- Click on the `Activation config` section in the node you want to add and fill in the values for \\\"when\\\" and \\\"is\\\".\\n!activate_config\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1154, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed", "document_node": "{\"id_\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dd45d45-00c4-4909-a54a-4b03f741623a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b462c2a1e9f20e051210c996e39d721335d61d44c64a788cae8cb40292e9d443\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"text\": \"Further details and important notes\\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\\n\\n !provide_default_value\\n\\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\\n\\n !output_bypassed\\n\\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \\\"Bypassed\\\", as shown in the figure below Show. There are three situations in which a node is bypassed.\\n\\n !bypassed_nodes\\n\\n\\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\\n\\n !activate_condition_always_met\\n\\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\\n\\n !activate_when_bypassed\\n\\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\\n\\n !dependencies_bypassed\", \"start_char_idx\": 2, \"end_char_idx\": 1434, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example", "document_node": "{\"id_\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c3e1eb6-23bf-44d1-bda4-5d37c208ee12\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c2d44a764f3b69bd15d3a78bec6b1601edecc6dfbf80ae99d4a6572eec2b15e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"text\": \"Example flow\\n\\nLet's illustrate how to use activate config with practical examples.\\n\\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\\n- Switch scenario: Explore conditional flow for switch scenarios. View Example\", \"start_char_idx\": 2, \"end_char_idx\": 260, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\n- Run and evaluate a flow", "document_node": "{\"id_\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"782a7b53-7c3c-448c-8908-a78835c5561f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"80d3825fe6697eff08a6a2e7aec7eef79ea6fec62bcbb9e6d0013befe8c13811\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"text\": \"Next steps\\n\\n- Run and evaluate a flow\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to construct test data based on documents\nThis guide will help to construct test data based on the provided documents.\nThe test data construction process contains three steps:\n- Split documents to smaller trunks.\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\n- Collect all the test data and remove empty values.", "document_node": "{\"id_\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d762c45d-76f8-44b7-ad01-f762c3b68201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fedab640d7be99800a8d2565a8cb7ec2ab9a551623a2612ab024014c2a0c6269\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"text\": \"How to construct test data based on documents\\nThis guide will help to construct test data based on the provided documents.\\nThe test data construction process contains three steps:\\n- Split documents to smaller trunks.\\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\\n- Collect all the test data and remove empty values.\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data preprocess\nEnter `test_data_gen_local` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c3acac60-fcab-445a-a4e2-189036d3baea\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"875f62cb506a3703f747a728b452b208ee7384cc39c747e00d1a5155dbb0ccbf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"text\": \"Data preprocess\\nEnter `test_data_gen_local` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 145, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get started\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\n> [!Note] This step can be skipped if you just want to have a try.\n\n- Enter test_data_gen_local folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen.py\n ```\n - The generated test data would be a data jsonl file with path you configured in `config.ini`", "document_node": "{\"id_\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dfc13dfd-4b2e-4016-a57a-2d2306d8e5d4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b6ad8f04373fe87782c782471ea659a4fd0e338f74b248a7de9aded5eced04c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"text\": \"Get started\\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\\n> [!Note] This step can be skipped if you just want to have a try.\\n\\n- Enter test_data_gen_local folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen.py\\n ```\\n - The generated test data would be a data jsonl file with path you configured in `config.ini`\", \"start_char_idx\": 2, \"end_char_idx\": 489, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Cloud\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.", "document_node": "{\"id_\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e5582dc9-2527-4689-a66b-3499f60d39ec\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aab6ff042514dbdc1c619bf071e11425c08125c6f6f889eb0c78445e1ddf3b34\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"text\": \"Cloud\\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.\", \"start_char_idx\": 2, \"end_char_idx\": 95, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"880d9550-3b75-4405-b690-dac4ffff2d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ffa284d6ce0438755afec9d24989afc353c5ab2bdee44cfe9dfcfa9287fa312f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"text\": \"Prerequisites\\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 146, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get started\n- Enter test_data_gen_pipeline folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen_pipeline.py\n ```\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.", "document_node": "{\"id_\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"920d1a8d-54b7-495d-bba0-92c616963af6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff72434cf5652a1df86ae0d8e0a4d1cdb20755160a3b5b04c210cc3d180afe4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"text\": \"Get started\\n- Enter test_data_gen_pipeline folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen_pipeline.py\\n ```\\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash", "document_node": "{\"id_\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"985feda6-5910-4344-8ac2-8e1f004066b7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7566d96cdda7049299b58e66d25859f99137724b7dcaee863800e26459f95290\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"text\": \"Deploy a flow using development server\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nWe are going to use the web-classification as\\nan example to show how to deploy a flow.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \\nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \\nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \\nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \\n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \\nvalue as a fallback.\\n\\n\\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1340, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::", "document_node": "{\"id_\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4726d80-ea7e-4fba-9613-db83617bb882\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac3a543e1dceee101173b9bc7ff893ee9fb5a9ceae85efa8194cdc97b790151a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"text\": \"Serve the flow at localhost:8080\\npf flow serve --source --port 8080 --host localhost\\n```\\n\\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\\n\\n!img\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\nIn visual editor, choose:\\n!img\\nthen choose format:\\n!img\\nthen in yaml editor:\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 364, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::", "document_node": "{\"id_\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5920919b-f0f6-4e82-8f36-b0ed794adca7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3a597bc0d35a21864ac97adf0631fa8b80c3c91c6f9cfdbf2792054289656b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"text\": \"Test endpoint\\n::::{tab-set}\\n:::{tab-item} Bash\\nYou could open another terminal to test the endpoint with the following command:\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\\n:::\\n:::{tab-item} PowerShell\\nYou could open another terminal to test the endpoint with the following command:\\n```powershell\\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -Method POST -ContentType \\\"application/json\\\"\\n```\\n:::\\n:::{tab-item} Test Page\\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 778, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ebc2e916-88ef-49b3-95f7-c181df18e83a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45ffa4d534f92a3990305fa76c49e9bc990763b6a85a443546545b8853581739\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using docker.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image.", "document_node": "{\"id_\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"001a5af0-2cb9-4089-997c-197892a18fd7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3cb96282cb3a51734f72174afeb7eb4676623f5801355e4cc3bcf5bf4f520338\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"text\": \"Deploy a flow using Docker\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are two steps to deploy a flow using docker:\\n1. Build the flow as docker format.\\n2. Build and run the docker image.\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf2f3ae5-ba72-4beb-86a4-1bc49436e1da\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0057da34d9137e38191046124bf42bcf8c1c1f4a027da0f73bac07c083ee4554\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1ae36579-078a-4568-8aba-c5dda9d14b7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8c279a743b10f1167ab4728059c1d90e3b2b5415f812715b657fd620826065ad\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.", "document_node": "{\"id_\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dc49828-c68f-4468-9df7-b79c065f957e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a10de6a73f84be1c1b016021afada237667a01c4928fd4fe49dd16f6339cc2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"text\": \"Deploy with Docker\\nWe are going to use the web-classification as\\nan example to show how to deploy with docker.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\", \"start_char_idx\": 2, \"end_char_idx\": 244, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cf6e2bc6-78d1-49ec-a697-cb2842d6fe1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ab5f3b806ff2c792734f1c1ad6c7bb6e3568b15939996aaab1650926bd7113b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"text\": \"Build a flow as docker format app\\n\\nUse the command below to build a flow as docker format app:\\n\\n```bash\\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\\n```\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 283, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```", "document_node": "{\"id_\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"787280bc-ae47-42e9-b7bb-2cf6d722902f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"025c08762a5530fe9b4d08fc2ee90bd910c36f27c24c6b442a3396d375a4c9c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\\n\\nRun the command below to build image:\\n\\n```bash\\ndocker build dist -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container.", "document_node": "{\"id_\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24c4f02a-f692-45ae-b6db-af8952922b50\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305bc2ac535b78373a93bbec09010ac6f2e3a0c5eda71ea5520198308366bd88\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"text\": \"Run Docker image\\n\\nRun the docker image will start a service to serve the flow inside the container.\", \"start_char_idx\": 2, \"end_char_idx\": 101, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4d1cbd08-9a15-4dae-9977-1a5b3e0e96e3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"454d361baede9825a6b5a25526bb0659e713e58685077d7448585205f0b99fc2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash", "document_node": "{\"id_\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d4a6eb86-2f08-48ea-a19d-db7442b672a3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2a9c5bb24d9dc83e164398fda42138afca7298371035a2e2e6b5e79b9586e95\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"text\": \"Run with `docker run`\\n\\nYou can run the docker image directly set via below commands:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 94, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```", "document_node": "{\"id_\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4937a2c8-60fb-4b10-ad90-64e2e0ad9203\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5db95208bb6ad14c49e70ef284d9838cf1c03aec34a0529b167858504277263\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"text\": \"The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 196, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```", "document_node": "{\"id_\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"094daa74-2704-419b-88a3-d90b6b14be78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d5595bcd64f47bff9d713811f8ea973e1e144428cdeba4c28f2c6e35f373537d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"text\": \"Test the endpoint\\nAfter start the service, you can use curl to test it:\\n\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 249, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbb19bfc-117b-4108-b0f0-782008d0d6f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d32afb6a7a32f2d7209c5e9c81a494466c7b79c8aec3991f80e2c38b7c7ed429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment.", "document_node": "{\"id_\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35233e62-7f70-4f02-bcb0-266eb8bab18d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edb6e94975ce9597a7289e364191cb2f0d9ccc41c1dc29ed10078ed5bffe6201\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"text\": \"Deploy a flow using Kubernetes\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are four steps to deploy a flow using Kubernetes:\\n1. Build the flow as docker format.\\n2. Build the docker image.\\n3. Create Kubernetes deployment yaml.\\n4. Apply the deployment.\", \"start_char_idx\": 2, \"end_char_idx\": 329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash", "document_node": "{\"id_\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"03b68070-8b3a-4e97-b6b5-2efdbd897d0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c32dac478d5c6812b1c1b508fd58be363fd98dc2b93fa1629c5780685a5395ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote that all dependent connections must be created before building as docker.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 163, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9d0ff802-5f7e-4d38-9298-2fe1d72d162a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28da9c8ae14ba1d288700ff08b67f3c64af26e9c9260c5acbe9d3bfce4f0a81c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 490, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a465868-961b-42fa-aff4-023aec92284b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"737ada3363594778b97169c88d91adcd82c3852d6ad94c3afededb851566d7e9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.", "document_node": "{\"id_\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cd6a5ee9-be8a-4cd3-a609-588043b8a5dc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb90193d094243e3f362f8f4834d27aae9ae1cc9c64e9cb898666ef5efcd7a22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"text\": \"Deploy with Kubernetes\\nWe are going to use the web-classification as\\nan example to show how to deploy with Kubernetes.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.\", \"start_char_idx\": 2, \"end_char_idx\": 494, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```", "document_node": "{\"id_\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca057cce-ae41-4870-86c6-2a7e11df6884\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf0826466e0b7135f7fa8f52748ebd1e0bf36b6c9b70923142f15679305f1509\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\\n\\nThen run the command below:\\n\\n```bash\\ncd \\ndocker build . -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 266, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```", "document_node": "{\"id_\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"416b4a60-5b95-4610-8818-5c0a950e70b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39fd3d4d93952fc682966479183abf5b004eb51f53bc7a39a608b97d417fa280\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"text\": \"Create Kubernetes deployment yaml.\\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\\n\\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\\n```bash\\nencoded_secret=$(echo -n | base64)\\n```\\n\\n```yaml\\n---\\nkind: Namespace\\napiVersion: v1\\nmetadata:\\n name: \\n---\\napiVersion: v1\\nkind: Secret\\nmetadata:\\n name: open-ai-connection-api-key\\n namespace: \\ntype: Opaque\\ndata:\\n open-ai-connection-api-key: \\n---\\napiVersion: v1\\nkind: Service\\nmetadata:\\n name: web-classification-service\\n namespace: \\nspec:\\n type: NodePort\\n ports:\\n - name: http\\n port: 8080\\n targetPort: 8080\\n nodePort: 30123\\n selector:\\n app: web-classification-serve-app\\n---\\napiVersion: apps/v1\\nkind: Deployment\\nmetadata:\\n name: web-classification-serve-app\\n namespace: \\nspec:\\n selector:\\n matchLabels:\\n app: web-classification-serve-app\\n template:\\n metadata:\\n labels:\\n app: web-classification-serve-app\\n spec:\\n containers:\\n - name: web-classification-serve-container\\n image: \\n imagePullPolicy: Never\\n ports:\\n - containerPort: 8080\\n env:\\n - name: OPEN_AI_CONNECTION_API_KEY\\n valueFrom:\\n secretKeyRef:\\n name: open-ai-connection-api-key\\n key: open-ai-connection-api-key\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1691, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.", "document_node": "{\"id_\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2f87d0-7ce6-424f-baf5-9a719bd9e6dd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"477a540f66a6f1ee65bfd60768d2a3d59c1dcadacee96a857fe7f25753276d75\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"text\": \"Apply the deployment.\\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\\n```bash\\nminikube start\\n```\\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\\n```bash\\nkubectl apply -f deployment.yaml\\n```\\nThis command will create the necessary pods to run your application within the cluster.\\n\\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.\", \"start_char_idx\": 2, \"end_char_idx\": 697, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```", "document_node": "{\"id_\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e957261-66c9-478e-a059-e80a3e8b0978\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b6370003e6a7da8b9a3332e4ffb0c781dac39e5cfb2e2ceb896790c8a4128be4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"text\": \"Retrieve flow service logs of the container\\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\\n\\n```bash\\nkubectl -n logs \\n```\", \"start_char_idx\": 2, \"end_char_idx\": 281, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fc445c62-3acb-4049-8230-38c9d8466d0b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8215b76f0bcab42a64d833c86863fbdb33dcc95da1fb59674394281d6c6fa40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```", "document_node": "{\"id_\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"272125df-0bcb-4bd6-bf09-c0ec657b16e6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50a786047950de8aa8f76dfa723527bb5c7e34deb5595b227792230410c0f3c1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"text\": \"Test the endpoint\\n- Option1:\\n\\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\\n To achieve this, execute the following command:\\n\\n ```bash\\n kubectl port-forward : -n \\n ```\\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\\n\\n- Option2:\\n\\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\\n\\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \\n\\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1405, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here.", "document_node": "{\"id_\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c90f24c2-70ef-4f4a-bec5-944c963c0017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f33e56b02f183c64dfe8e88bb3d10c17054eb93b672d3dfc9f7b81353b318734\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"text\": \"Next steps\\n- Try the example here.\", \"start_char_idx\": 2, \"end_char_idx\": 36, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.", "document_node": "{\"id_\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"78c930c3-0d07-47fa-bcb4-c05ee6801638\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce667521e60986a068e5688e6f7084f84281c241bc239aeacd088d8815f5d142\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"text\": \"Distribute flow as executable app\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nWe are going to use the web-classification as\\nan example to show how to distribute flow as executable app with Pyinstaller.\\n\\n\\nPlease ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \\n\\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.\", \"start_char_idx\": 2, \"end_char_idx\": 1262, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash", "document_node": "{\"id_\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"889137df-2303-4e28-9e25-af03a3dade9a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"788efa4a3e263596c0e89a318492f454d61b1947a3249b5817814acecccddf69\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"text\": \"Build a flow as executable format\\nNote that all dependent connections must be created before building as executable.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```", "document_node": "{\"id_\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b8cb107-8895-47b3-bb7b-4afda0994fcf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a5b966cba851cc99e639ac17d4e9ce03f6d8ec9b948b2b2ec507aa7e1a1fa00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as executable format:\\n```bash\\npf flow build --source --output --format executable\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 298, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files.", "document_node": "{\"id_\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cbcb9eaf-2132-477b-8703-ab3179413b0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60e4cbfdadc24044a4f6ff9eff16829666816426530e507bf35ac475af6e80ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"text\": \"Executable format folder structure\\n\\nExported files & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files.\\n- connections: the folder contains yaml files to create all related connections.\\n- app.py: the entry file is included as the entry point for the bundled application.\\n- app.spec: the spec file tells PyInstaller how to process your script.\\n- main.py: it will start streamlit service and be called by the entry file.\\n- settings.json: a json file to store the settings of the executable application.\\n- build: a folder contains various log and working files.\\n- dist: a folder contains the executable application.\\n- README.md: Simple introduction of the files.\", \"start_char_idx\": 2, \"end_char_idx\": 733, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```", "document_node": "{\"id_\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8754ca46-b358-442e-85aa-2dd01a1c60b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"525024450d56483fc20362c341d7af6062113e5f8fe6518a8b279a5c130d6ff3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"text\": \"A template script of the entry file\\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \\n\\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\\n\\n```python\\nimport os\\nimport sys\\n\\nfrom promptflow._cli._pf._connection import create_connection\\nfrom streamlit.web import cli as st_cli\\nfrom streamlit.runtime import exists\\n\\nfrom main import start\\n\\ndef is_yaml_file(file_path):\\n _, file_extension = os.path.splitext(file_path)\\n return file_extension.lower() in ('.yaml', '.yml')\\n\\ndef create_connections(directory_path) -> None:\\n for root, dirs, files in os.walk(directory_path):\\n for file in files:\\n file_path = os.path.join(root, file)\\n if is_yaml_file(file_path):\\n create_connection(file_path)\\n\\n\\nif __name__ == \\\"__main__\\\":\\n create_connections(os.path.join(os.path.dirname(__file__), \\\"connections\\\"))\\n if exists():\\n start()\\n else:\\n main_script = os.path.join(os.path.dirname(__file__), \\\"main.py\\\")\\n sys.argv = [\\\"streamlit\\\", \\\"run\\\", main_script, \\\"--global.developmentMode=false\\\"]\\n st_cli.main(prog_name=\\\"streamlit\\\")\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1486, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec", "document_node": "{\"id_\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35fb4943-f149-41fa-bdd4-d7e134bf38ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3359e5ab1140c765b2cec249fad745ee49bf26f68fb798200109fd048f8ea886\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"text\": \"A template script of the spec file\\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\\n\\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\\n\\n```spec\", \"start_char_idx\": 2, \"end_char_idx\": 626, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```", "document_node": "{\"id_\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e2b8a188-7744-48aa-bd3e-88622db05d16\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92c55ce053208bb4f5a6a40a6658a2620ec99440bbcb2e2984a892b3ab2b41ec\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"text\": \"-*- mode: python ; coding: utf-8 -*-\\nfrom PyInstaller.utils.hooks import collect_data_files\\nfrom PyInstaller.utils.hooks import copy_metadata\\n\\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\\ndatas += collect_data_files('streamlit')\\ndatas += copy_metadata('streamlit')\\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\\ndatas += copy_metadata('keyrings.alt')\\ndatas += collect_data_files('streamlit_quill')\\n\\nblock_cipher = None\\n\\n\\na = Analysis(\\n ['app.py', 'main.py'],\\n pathex=[],\\n binaries=[],\\n datas=datas,\\n hiddenimports=['bs4'],\\n hookspath=[],\\n hooksconfig={},\\n runtime_hooks=[],\\n excludes=[],\\n win_no_prefer_redirects=False,\\n win_private_assemblies=False,\\n cipher=block_cipher,\\n noarchive=False,\\n)\\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\\n\\nexe = EXE(\\n pyz,\\n a.scripts,\\n a.binaries,\\n a.zipfiles,\\n a.datas,\\n [],\\n name='app',\\n debug=False,\\n bootloader_ignore_signals=False,\\n strip=False,\\n upx=True,\\n upx_exclude=[],\\n runtime_tmpdir=None,\\n console=True,\\n disable_windowed_traceback=False,\\n argv_emulation=False,\\n target_arch=None,\\n codesign_identity=None,\\n entitlements_file=None,\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1331, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.", "document_node": "{\"id_\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbbf6b9c-6c93-4225-9464-811c74b323b1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"137b06713f5e2940b2fe428d41780bb47007f0e7ec4af0aae52c6ed2a843f992\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"text\": \"The bundled application using Pyinstaller\\nOnce you've build a flow as executable format following Build a flow as executable format.\\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```", "document_node": "{\"id_\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0dd26999-3784-4781-b921-16dc8238be64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554ae32ca1c480322848743e9c6da4fd7418108c6046d6cac9f2b84fba6edd71\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 501, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).", "document_node": "{\"id_\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c2d3b808-b23f-43eb-a47c-1222042cef68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9e38dad6f79b85483297a2e961c7074d5eb7b33e144a833dfeb034ffc8d6380\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"text\": \"Test the endpoint\\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \\n\\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\\n\\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\\n\\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).\", \"start_char_idx\": 2, \"end_char_idx\": 819, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.", "document_node": "{\"id_\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c33c3b24-6d2f-4008-886e-5f909d48d67f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c51e0c6b8fd6ab482b88267abb541c19a26e8a5ace41312d12b6934cfc961ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"text\": \"Known issues\\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.\", \"start_char_idx\": 2, \"end_char_idx\": 162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Try the example here", "document_node": "{\"id_\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a01c5abe-5e5a-4ddb-add2-e3860e52b7cc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e568ec67bd14372ad8610019228abfcab0577cf33fc2d5c498a88ba6889ba595\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"text\": \"Next steps\\n- Try the example here\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fedee87-d831-42e5-8868-b687b8669cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7fee890cde8a5e564cd8a0ac6f8e2e91acb42d8f07a7afb781d3e7fe3abad5de\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"text\": \"Develop chat flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 314, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"459ea5a0-07b2-4018-9d73-f5c12560a9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"34672e2e9b5d672a905e718c868c88a5dc1f874f92b883d54f30ea8c8bbc7251\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"text\": \"Flow input data\\n\\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\\n\\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\\n\\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\\n \\n An example of chat history:\\n ```python\\n [\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What types of container software there are?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"There are several types of container software available, including: Docker, Kubernetes\\\"}},\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What's the different between them?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\\\"}},\\n ] \\n ```\\n\\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\\n```yaml\\ninputs:\\n chat_history:\\n type: list\\n is_chat_history: true\\n default: []\\n question:\\n type: string\\n is_chat_input: true\\n default: What is ChatGPT?\\n```\\n\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 1811, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19e1d3da-0011-44c6-842e-f43872513fee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7174bd166b0fb96b0c3c56f110b7bf6b469e98368c15514bfc18c5bda0333ced\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow.", "document_node": "{\"id_\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec04b974-2730-40eb-b576-9ff5b98ec67a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f683434028ff51d70bcc3e19d09c958ea5fbac263b5b572a16e8cfcc6dfe623\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\\n\\nFor more information see chain your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```", "document_node": "{\"id_\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13f31c7e-48b2-4c8b-a22c-75a2ed4ef4a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09947add90687052194ef8af3b2f29e05eae203b6f2be62d68b64ed4e0c165e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"text\": \"Set flow output\\n\\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\\n\\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\\n\\n```yaml\\noutputs:\\n answer:\\n type: string\\n reference: ${chat.output}\\n is_chat_output: true\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 453, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.", "document_node": "{\"id_\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8155fe6d-e44d-4b32-a92d-cfd53d2d1dc9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"050307129fb74fe69bb453b44fb4578c009429623df62e027e90bd000d14aea4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"text\": \"Develop evaluation flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\\n\\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\\n- `Inputs/Outputs definition`\\n- `Nodes`\\n- `Chain nodes in a flow`\\n\\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.", "document_node": "{\"id_\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9af9790b-674a-4a32-b26d-76d74f80c201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30a482680af6d77ff4a32b07e7e70496af7d8e659d41e9ddd9bc1a3d2a9e799c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"text\": \"Evaluation flow example\\n\\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.\", \"start_char_idx\": 2, \"end_char_idx\": 439, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.", "document_node": "{\"id_\": \"f67eae57-2228-4768-bf9e-752182255315\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a928698-f22c-4012-85c2-e736a3205a32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"806a38502591403dda37598c10e796b0d0b5c7da92670db5caa94bd4059efa78\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"text\": \"Flow inputs\\n\\nThe flow `eval-classification-accuracy` contains two inputs:\\n\\n```yaml\\ninputs:\\n groundtruth:\\n type: string\\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\\n default: APP\\n prediction:\\n type: string\\n description: The actual predicted outputs that your flow produces.\\n default: APP\\n```\\n\\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \\n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\\n\\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1174, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.", "document_node": "{\"id_\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00b01149-18e5-4fb6-af7c-d1074b90fccb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de34c0d3cae520dc7074bb45e7e48909c31b019d26a7cb740829def7c0c2acdd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"text\": \"Aggregation node\\n\\n\\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\\n\\n```yaml\\n- name: grade\\n type: python\\n source:\\n type: code\\n path: grade.py\\n inputs:\\n groundtruth: ${inputs.groundtruth}\\n prediction: ${inputs.prediction}\\n```\\n\\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\\n\\n```python\\nfrom promptflow import tool\\n\\n@tool\\ndef grade(groundtruth: str, prediction: str):\\n return \\\"Correct\\\" if groundtruth.lower() == prediction.lower() else \\\"Incorrect\\\"\\n```\\n\\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\\n1. It has an attribute `aggregation` set to be `true`.\\n\\n```yaml\\n- name: calculate_accuracy\\n type: python\\n source:\\n type: code\\n path: calculate_accuracy.py\\n inputs:\\n grades: ${grade.output}\\n aggregation: true # Add this attribute to make it an aggregation node\\n```\\n\\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef calculate_accuracy(grades: List[str]):\\n result = []\\n for index in range(len(grades)):\\n grade = grades[index]\\n result.append(grade)\\n\\n # calculate accuracy for each variant\\n accuracy = round((result.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(\\\"accuracy\\\", accuracy)\\n\\n return result\\n```\\n\\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Channel\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\n\\n And we provides a data file like this:\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Channel\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nThen the `grades` value would be `[\\\"Correct\\\", \\\"Correct\\\", \\\"Incorrect\\\"]`, and the final accuracy is `0.67`. \\n\\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.\", \"start_char_idx\": 2, \"end_char_idx\": 2278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`.", "document_node": "{\"id_\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"952a2672-5398-4540-b942-4d7b4e729b92\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"822605742d13841acd10ffcea5db1d1a13e3e30e09dbb36b3e51a8d80046c79e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"text\": \"More about the list parameter\\n\\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\\n\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\\n\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nIn this case, the `grades` value would be `[\\\"Correct\\\", \\\"Incorrect\\\"]` and the accuracy is `0.5`.\", \"start_char_idx\": 2, \"end_char_idx\": 920, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img", "document_node": "{\"id_\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f7fa17f-8dee-470a-916d-e55d9fe11f1e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60ff341156316a69a77efdcace6fd85fa977b463e106c0110ba68ba78da5f0b5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"text\": \"How to set aggregation node in VS Code Extention\\n\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img", "document_node": "{\"id_\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a7d7d4cd-91ab-4d18-9812-73abab2aaac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62f9779b95c01ecabbbe5cdcda006b117a8dd30ff024f26bd9ec2d33ad4aa7f6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"text\": \"How to log metrics\\n:::{admonition} Limitation\\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\\n:::\\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \\n\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef example_log_metrics(grades: List[str]):\\n # this node is an aggregation node so it accepts a list of grades\\n metric_key = \\\"accuracy\\\"\\n metric_value = round((grades.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(metric_key, metric_value)\\n```\\n\\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 777, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"242a77a2-a306-40bf-93d7-cd6878f5b9bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97d57345e8b5efdb1c430e93e2262ab8995b9b9b3fbf17e9738b3decaf201c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"text\": \"Develop standard flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 322, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types.", "document_node": "{\"id_\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9635de74-544b-4e42-b80e-66f4a9558c00\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668b015e6c989c7d86e3dfcad898c06c44f445fe96bd6d6fccf909a044c1ede0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"text\": \"Flow input data\\nThe flow input data is the data that you want to process in your flow. \\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a flow input in inputs section of flow yaml.\\n```yaml\\ninputs:\\n url:\\n type: string\\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \\nand the input value.\\n\\n!flow_input\\n:::\\n\\n::::\\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\\nFor more input types in a python tool, please refer to Input types.\", \"start_char_idx\": 2, \"end_char_idx\": 757, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.", "document_node": "{\"id_\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"919ca595-35ff-4dba-8a31-26b416b7e3ab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0cf6fa20af96fe27dfaf6ee9484693e4513ea19ec3d3ef8e6b56ebcb0ecaea23\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\", \"start_char_idx\": 2, \"end_char_idx\": 212, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::", "document_node": "{\"id_\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c60c3d4-098c-4952-ba3b-0de0506f55f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0bcdc43c78e08ebcf9feadfbe7d897b9998f6b922626ed3c1870d182634403c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"text\": \"Add tool as your need\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\\n\\n!add_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool", "document_node": "{\"id_\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fdf5dd30-8270-4fee-aa1a-abcfbcbb512b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c3fadc7c5b72b98e4ba684a95f971986f4df0034a0a614271c2ffc78074df271\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"text\": \"Edit tool\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\\n\\n```python\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::", "document_node": "{\"id_\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b15324bb-86ed-44cb-bd91-796bc99a3242\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b2175984579bdcc522aadd3d3f03eac2d874f191c3230e9d5f99a7406f02ab54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"text\": \"The inputs section will change based on the arguments of the tool function, after you save the code\\n@tool\\ndef my_python_tool(input1: str) -> str:\\n return 'hello ' + input1\\n```\\n\\nWe also provide an LLM tool prompt below.\\n\\n```jinja\\nPlease summarize the following text in one paragraph. 100 words.\\nDo not add any information that is not in the text.\\nText: {{text}}\\nSummary:\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \\nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \\ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\\n!edit_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 938, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details.", "document_node": "{\"id_\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8372ff3d-7692-45b9-ac7d-81f0f40101b5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fdbc523c40c6af31143083203d50b7b08d2ea8520099eeda080947118eab3d00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"text\": \"Create connection\\nPlease refer to the Create necessary connections for details.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.", "document_node": "{\"id_\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01934a78-1481-496a-8449-4e8fe6e4a85f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"17c34f9a2db75c40a67d3f3bb44546b8ffe352ba6f837e324a7955cbf41877b2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\", \"start_char_idx\": 2, \"end_char_idx\": 114, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```", "document_node": "{\"id_\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86c4ea6f-359c-484e-b68e-431c7adcf5c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45184bbd7413f02695ec0459bc753bb0bc538058b5e19dc48636c3bb7e15f50c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"text\": \"Define LLM node interface\\nLLM node has only one output, the completion given by LLM provider.\\n\\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \\nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \\ntemplating language. For example:\\n\\n```jinja\\nYour task is to classify a given url into one of the following types:\\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\\nThe classification will be based on the url, the webpage text content summary, or both.\\n\\nHere are a few examples:\\n{% for ex in examples %}\\nURL: {{ex.url}}\\nText content: {{ex.text_content}}\\nOUTPUT:\\n{\\\"category\\\": \\\"{{ex.category}}\\\", \\\"evidence\\\": \\\"{{ex.evidence}}\\\"}\\n\\n{% endfor %}\\n\\nFor a given URL : {{url}}, and text content: {{text_content}}.\\nClassify above url to complete the category and indicate evidence.\\nOUTPUT:\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 958, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```", "document_node": "{\"id_\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0d6a1e23-9c61-456e-b5f8-6646774e7517\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7098a85fc27d133c1dd382abf3c7c82f3704b115745129d0b4c63e59891bbcb6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"text\": \"Define Python node interface\\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \\nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\\nFor example:\\n\\n```python\\nimport json\\nfrom promptflow import tool\\n\\n@tool\\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\\n try:\\n print(input_str2)\\n return json.loads(input_str)\\n except Exception as e:\\n print(\\\"input is not valid, error: {}\\\".format(e))\\n return {\\\"category\\\": \\\"None\\\", \\\"evidence\\\": \\\"None\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 595, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together.", "document_node": "{\"id_\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2b337a61-282c-4aa0-8cc2-a303344a3a87\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"72154d54360f4b5a82884b63734ac5365a69ed681123ba1e32eb8718628ee58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"text\": \"Link nodes together\\nAfter the interface is defined, you can use:\\n\\n- ${inputs.key} to link with flow input.\\n- ${upstream_node_name.output} to link with single-output upstream node.\\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\\n\\nBelow are common scenarios for linking nodes together.\", \"start_char_idx\": 2, \"end_char_idx\": 313, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.", "document_node": "{\"id_\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c06825b-2eca-437e-81ef-b400683e5107\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dc503dd0dd29d203ef8868753fef7c97754d409dead2aab234f87acf6388f82b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"text\": \"Scenario 1 - Link LLM node with flow input and single-output upstream node\\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \\nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link the LLM node input with flow input by `${inputs.url}`. \\nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \\nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n url: ${inputs.url} # Link with flow input\\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \\nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \\n\\n!link_llm_with_flow_input_single_output_node\\n:::\\n\\n::::\\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \\n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1746, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.", "document_node": "{\"id_\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57a1605b-80c4-4052-8504-33374b92caee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8cf98f614b216b0d506c5cbbb9581ef3ca68bad51e3877c4935b7ef16ecb6e4c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"text\": \"Scenario 2 - Link LLM node with multi-output upstream node\\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \\nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\\n\\n!link_llm_with_multi_output_node\\n:::\\n::::\\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1273, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.", "document_node": "{\"id_\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8126884c-df49-43ba-9d3f-1a9638cd235d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a42c7be5b7c364c1f60b09c4d2756084cd1c9d628ef3fad2380f9b736ce02b20\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"text\": \"Scenario 3 - Link Python node with upstream node/flow input\\nAfter you add a new Python node and edit the code file like Define Python node interface], \\ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \\nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n```yaml\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs:\\n input_str: ${inputs.url} # Link Python node with flow input\\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n!link_python_with_flow_node_input\\n:::\\n\\n::::\\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \\ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1045, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::", "document_node": "{\"id_\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c8228df-9c72-4af5-b9c4-7369ed0f78e8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"35e2f7644a2153debed83c13170ff3cc72a2a0396587f4c47bebb3e814c9c005\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"text\": \"Set flow output\\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \\nmultiple nodes in one place. Moreover, flow output helps:\\n\\n- Check bulk test results in one single table.\\n- Define evaluation interface mapping.\\n- Set deployment response schema.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \\nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \\n`convert_to_dict`.\\n\\n```yaml\\noutputs:\\n category:\\n type: string\\n reference: ${convert_to_dict.output.category}\\n evidence:\\n type: string\\n reference: ${convert_to_dict.output.evidence}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \\nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \\n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\\n\\n!flow_output\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1194, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.", "document_node": "{\"id_\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"66907d7f-5f3f-48c2-9669-2c366a8ae143\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"75e4c5eee350016added3ec9fe497df916fbd71d627b305a3190eb538cc362a4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"text\": \"Referencing external files/folders in a flow\\n\\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\\n\\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/classify_with_llm.jinja2\\n- ../web-classification/convert_to_dict.py\\n- ../web-classification/fetch_text_content_from_url.py\\n- ../web-classification/prepare_examples.py\\n- ../web-classification/summarize_text_content.jinja2\\n- ../web-classification/summarize_text_content__variant_1.jinja2\\n```\\n\\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\\n\\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n```\\n\\nThe entry file \\\"fetch_text_content_from_url.py\\\" of the tool node \\\"fetch_text_content_from_url\\\" is located in \\\"../web-classification/fetch_text_content_from_url.py\\\", as specified in the additional_includes field. The same applies to the \\\"summarize_text_content\\\" tool nodes.\\n\\n> **Note**:\\n>\\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\\nTake the following YAML structure as an example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/prepare_examples.py\\n- ../tmp/prepare_examples.py\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n``` \\n\\nIn this case, the system will use \\\"../tmp/prepare_examples.py\\\" as the entry file for the tool node \\\"prepare_examples\\\". Even if there is a file named \\\"prepare_examples.py\\\" in the flow folder, the system will still use the file \\\"../tmp/prepare_examples.py\\\" specified in the `additional_includes` field.\\n\\n> Tips:\\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.\", \"start_char_idx\": 2, \"end_char_idx\": 3451, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.", "document_node": "{\"id_\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2b7611-b6e8-41d5-bcb7-857e344fb92a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"14430280f768c113dbf9e583b57be7eb327a7edbaf80889e72c017b668b89311\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"text\": \"Adding a tool icon\\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\\n\\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.\", \"start_char_idx\": 2, \"end_char_idx\": 295, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference.", "document_node": "{\"id_\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57058ab8-fa89-4e8a-a86f-8f8f6d8843bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb4c72a52e728f4c06cb906c2535c4d2d1e3e2b9c9ccf274d6c6fa6a2257c4c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"text\": \"Prerequisites\\n\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\\n- Create a tool package as described in Create and Use Tool Package.\\n- Prepare custom icon image that meets these requirements:\\n\\n - Use PNG, JPG or BMP format.\\n - 16x16 pixels to prevent distortion when resizing.\\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \\n\\n See this example as a reference.\", \"start_char_idx\": 2, \"end_char_idx\": 526, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Add tool icon with _icon_ parameter", "document_node": "{\"id_\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5b08ae97-5546-4d8a-8170-1e00ceabc742\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"200723951d139ca9f747a814fe55f43bf4c437d9ca9165060bd9ec9962224d93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"text\": \"Add tool icon with _icon_ parameter\", \"start_char_idx\": 2, \"end_char_idx\": 37, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```", "document_node": "{\"id_\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"04cb4765-6550-47b7-9cee-1ae8b0d9dfef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bfa267daed05b823404227af4ca8eaabad2e04b3069149430390fe220d5df245\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"text\": \"Initialize a package tool with icon\\nYou can use pf tool init to initialize a package tool with icon:\\n```bash\\npf tool init --package --tool --set icon=\\n```\\n\\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\\n```python\\nfrom pathlib import Path\\n\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n icon=Path(__file__).parent.parent / \\\"icons\\\" / \\\"custom-tool-icon.png\\\"\\n)\\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\\n\\nThe folder structure of the generated tool package is as follows:\\n```\\n\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u251c\\u2500\\u2500\\u2500icons\\n\\u2502 \\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500\\n .py\\n utils.py\\n __init__.py\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1222, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension", "document_node": "{\"id_\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a6b4670f-1911-41c2-816e-2afb835bce01\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1abe48bedddbcc1787d670a0952e7a3a82f2de7afce76d2d985ec9d05645a0cd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"text\": \"Verify the tool icon in VS Code extension\\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \\n!custom-tool-with-icon-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 176, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```", "document_node": "{\"id_\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9538f81c-1db6-4c2a-bbb5-ef36ca94fe44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbae9925b9e8426daba0ea2c01d494ed28a0e6dfd7437106812478371a299361\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"text\": \"FAQ\\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\\n```\\npython \\\\tool\\\\convert_image_to_data_url.py --image-path -o \\n```\\nFor example:\\n```\\npython D:\\\\proj\\\\github\\\\promptflow\\\\scripts\\\\tool\\\\convert_image_to_data_url.py --image-path D:\\\\proj\\\\github\\\\promptflow\\\\examples\\\\tools\\\\tool-package-quickstart\\\\my_tool_package\\\\icons\\\\custom-tool-icon.png -o output.html\\n```\\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\\n```html\\n\\n\\n\\n\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 580, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```", "document_node": "{\"id_\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"699ce5b2-187c-46f3-9f9c-b3b535acd91c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d707888b7220646c246f2b7886f82a2e315b193744d4f9c407ffd60a44e1c6a3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"text\": \"Can I add a tool icon to an existing tool package\\n\\nYou can follow these steps to add an icon to an existing package tool:\\n1. Copy the icon image to the package folder.\\n2. Configure the icon for the tool.\\n\\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\\n ```python\\n from promptflow import tool\\n\\n @tool(name=\\\"tool_name\\\", icon=)\\n def tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n ```\\n3. Update `MANIFEST.in` in the package folder.\\n\\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\\n ```\\n include \\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 769, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.", "document_node": "{\"id_\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca4ccdf3-090d-45f9-9d6a-07979afc72ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3d4af681b648feaf107b311553825afe2354879d3aec8e50615a0ed039d2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"text\": \"Can I add tool icons for dark and light mode separately?\\nYes, you can add the tool icon data to the tool code as follows:\\n```python\\nfrom promptflow import tool\\n\\n@tool(name=\\\"tool_name\\\", icon_dark=, icon_light=)\\ndef tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n```\\n\\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\\n```python\\npf tool init --tool --set icon_dark= icon_light=\\n```\\n\\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.\", \"start_char_idx\": 2, \"end_char_idx\": 756, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field.", "document_node": "{\"id_\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01518a9e-e18d-4949-9626-094903eea51c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be5cd30b0f09f966dbb2e5f5edbbbd36d25301c73f444f5f31f9585dba4c0c81\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"text\": \"Adding category and tags for tool\\n\\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\\n\\n| Attribute | Type | Required | Description |\\n| --------- | ---- | -------- | ----------- |\\n| category | str | No | Organizes tools into folders by common features. |\\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\\n\\n**Important Notes:**\\n- Tools without an assigned category will be listed in the root folder.\\n- Tools lacking tags will display an empty tags field.\", \"start_char_idx\": 2, \"end_char_idx\": 1063, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.", "document_node": "{\"id_\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8779355d-d614-4b16-835d-d0721a33dc45\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74313f42ccdbca8b27db5e01299294ae7b0bf1a6ec47b19245225df77fa5f403\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 186, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```", "document_node": "{\"id_\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8d6db4b6-5a82-49d7-ac61-f26dfe211484\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8444fd90e8cf147e712f4a38ad588c732d2520d4f678a8b1455c1853ec50da8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"text\": \"How to add category and tags for a tool\\n\\nYou can use pf tool init to initialize a package tool with category and tags:\\n```python\\npf tool init --package --tool --set category= tags=\\n\\n```\\n\\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\\n```python\\npf tool init --tool my_tool --set name=\\\"My First Tool\\\" description=\\\"This is my first tool\\\" category=\\\"test_tool\\\" tags=\\\"{'tag1':'value1','tag2':'value2'}\\\"\\n```\\nThe generated tool script is as follows, where category and tags have been configured on the tool:\\n```python\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n category=\\\"test_tool\\\",\\n tags={\\\"tag1\\\": \\\"value1\\\", \\\"tag2\\\": \\\"value2\\\"},\\n)\\ndef my_tool(self, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1189, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag", "document_node": "{\"id_\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddf33403-cee1-4e76-a2ab-f6ec20ab5391\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce8dfca466c3c5f8a3b0f25cefa6575a14aac45fc4c6bd71b81025b60a999429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"text\": \"Tool with category and tags experience in VS Code extension\\nFollow the steps to use your tool via the VS Code extension.\\n- Experience in the tool tree\\n!category_and_tags_in_tool_tree\\n\\n- Experience in the tool list\\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\\n!category_and_tags_in_tool_list\\nFurthermore, you have the option to search or filter tools based on tags:\\n!filter_tools_by_tag\", \"start_char_idx\": 2, \"end_char_idx\": 443, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```", "document_node": "{\"id_\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"344346f5-1b0d-44f2-9731-80d27521e130\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4efeae08cd9f495b68b9d5c9738dbcf9caa03eae09cf94a5fc1567bd33f706d5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"text\": \"FAQ\\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\\n```python\\n@tool(\\n name=\\\"tool_name\\\",\\n description=\\\"This is tool_name tool\\\",\\n category=,\\n tags=,\\n)\\ndef tool_name(input_text: str) -> str:\\n # tool logic\\n pass\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 285, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list", "document_node": "{\"id_\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8eb7c175-5eb4-4be1-904f-f815a877641c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"761b3c022375969240ebb1501804424057266c488c43981e362d1b0a23a21831\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"text\": \"Create and use tool package\\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\\n\\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\\n\\nAfter successful installation of the package, your custom \\\"tool\\\" will show up in VSCode extension as below: \\n!custom-tool-list\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.", "document_node": "{\"id_\": \"936062d7-da6f-425e-8071-eec693938da0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4e9a3b-17ed-41b4-af95-541b9285769d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6d0592c1fbf449100098a1897232c851f0023246794d1404df65486e26b30ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"text\": \"Create your own tool package\\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.\", \"start_char_idx\": 2, \"end_char_idx\": 150, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```", "document_node": "{\"id_\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02d44090-c629-4857-8fb8-f857f9743f31\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c283b0aa603e66d9c0593d1f97704896afe43f3c0562e30fdd8b1490164d4b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"text\": \"Prerequisites\\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\\n```\\npip install promptflow\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure.", "document_node": "{\"id_\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cb076bf-bda4-491f-b36b-90646bf39825\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4d88291fa44db81f7df84aa930a343b8e56aa76fbd22cd6831525a828d2bdb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"text\": \"Create custom tool package\\nYou can use pf tool init to initialize a package tool in current folder:\\n\\n```bash\\npf tool init --package --tool \\n\\n```\\nFor example:\\n```bash\\npf tool init --package hello_world --tool hello_world_tool\\n```\\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\\n\\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\\n\\n```\\nhello_world/\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500hello_world/\\n hello_world_tool.py\\n utils.py\\n __init__.py\\n```\\n\\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\\n\\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \\n\\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\\n ```python\\n entry_points={\\n \\\"package_tools\\\": [\\\" = :\\\"],\\n },\\n ```\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\", \"start_char_idx\": 2, \"end_char_idx\": 3024, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.", "document_node": "{\"id_\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb45998c-8b7b-47c6-8563-3cc43e460689\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e56c43e15838921293454392a9f5431b91b0d337bc691b653cef4250b6d5e52b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"text\": \"Build and share the tool package\\n Execute the following command in the tool package root directory to build your tool package:\\n ```\\n python setup.py sdist bdist_wheel\\n ```\\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\\n\\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\\n\\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\\n\\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.\", \"start_char_idx\": 2, \"end_char_idx\": 1081, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension", "document_node": "{\"id_\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a2aac4b6-dee0-40c8-b78f-fa6c85823c0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6dac8b1537a6e23487b63d97bffeeda30df26f43280d740357e8e84c36c3081a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"text\": \"Use your tool from VSCode Extension\\n* Step1: Install Prompt flow for VS Code extension. \\n\\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\\n ```\\n (local_test) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> conda activate prompt-flow\\n (prompt-flow) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> pip install .\\\\dist\\\\my_tools_package-0.0.1-py3-none-any.whl\\n ``` \\n\\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\\n!auto-list-tool-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 745, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.", "document_node": "{\"id_\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25ceaf4b-d75c-452e-b038-cb1cff034017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a67937099d4ff70a170e33ffc30f7d928d2833bfa58a1bbe333e21e7507e09e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"text\": \"FAQs\\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\\n\\n 1. Make sure to install the tool package in your conda environment before executing this script.\\n 2. Create a python file anywhere and copy the content below into it.\\n ```python\\n import importlib\\n import importlib.metadata\\n\\n def test():\\n \\\"\\\"\\\"List all package tools information using the `package-tools` entry point.\\n\\n This function iterates through all entry points registered under the group \\\"package_tools.\\\"\\n For each tool, it imports the associated module to ensure its validity and then prints\\n information about the tool.\\n\\n Note:\\n - Make sure your package is correctly packed to appear in the list.\\n - The module is imported to validate its presence and correctness.\\n\\n Example of tool information printed:\\n ----identifier\\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\\n \\\"\\\"\\\"\\n entry_points = importlib.metadata.entry_points()\\n PACKAGE_TOOLS_ENTRY = \\\"package_tools\\\"\\n if isinstance(entry_points, list):\\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\\n else:\\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\\n for entry_point in entry_points:\\n list_tool_func = entry_point.load()\\n package_tools = list_tool_func()\\n\\n for identifier, tool in package_tools.items():\\n importlib.import_module(tool[\\\"module\\\"]) # Import the module to ensure its validity\\n print(f\\\"----{identifier}\\\\n{tool}\\\")\\n\\n if __name__ == \\\"__main__\\\":\\n test()\\n ```\\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.\", \"start_char_idx\": 2, \"end_char_idx\": 2062, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.", "document_node": "{\"id_\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"361d2447-b4f8-4f35-a1af-8892d249e13a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"55e3663e73f77321999c9beef546505b42179a322bae4b28bb738f35af78f7c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"text\": \"Why am I unable to upload package to PyPI?\\n* Make sure that the entered username and password of your PyPI account are accurate.\\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.\", \"start_char_idx\": 2, \"end_char_idx\": 654, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs", "document_node": "{\"id_\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4c66da-b14f-452c-9927-49b39d9cd181\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8d7ea9fb7c1ff5d72950bbb6b92aa6aafe99722a29b7723c16ec2fae992a4d83\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"text\": \"Advanced features\\n- Add a Tool Icon \\n- Add Category and Tags for Tool \\n- Create and Use Your Own Custom Strong Type Connection \\n- Customize an LLM Tool \\n- Use File Path as Tool Input \\n- Create a Dynamic List Tool Input \\n- Create Cascading Tool Inputs\", \"start_char_idx\": 2, \"end_char_idx\": 258, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.", "document_node": "{\"id_\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f82dbbc6-86b4-4928-8eec-c50b955110f6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbfca4e40603faa2d69519faaf0e6a2bee1c43b0f5f9d625ef9172cf40e2d822\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"text\": \"Creating cascading tool inputs\\n\\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.\", \"start_char_idx\": 2, \"end_char_idx\": 303, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6da446b1-c160-474d-89f3-f9f3659daaa0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f552409c79c5e4003de24d7f1a2f627a4005d8711975f42568830bb585d7fc54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"text\": \"Prerequisites\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 237, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```", "document_node": "{\"id_\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5fbd0902-ccbb-4e1e-b205-f191c87d3f39\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fae50d17a2ec06631c825bbd2772d5c2952857c4632a2670168971f1401afe09\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"text\": \"Create a tool with cascading inputs\\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\\n\\nDevelop the tool function, following the cascading inputs example. Key points:\\n * Use the `@tool` decorator to mark the function as a tool.\\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\\n * Conditionally use inputs in the tool logic based on `user_type`.\\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\\n\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass UserType(str, Enum):\\n STUDENT = \\\"student\\\"\\n TEACHER = \\\"teacher\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Enabled By Value\\\",\\n description=\\\"This is my tool with enabled by value\\\",\\n input_settings={\\n \\\"teacher_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.TEACHER]),\\n \\\"student_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.STUDENT]),\\n }\\n)\\ndef my_tool(user_type: UserType, student_id: str = \\\"\\\", teacher_id: str = \\\"\\\") -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\n :param user_type: user type, student or teacher.\\n :param student_id: student id.\\n :param teacher_id: teacher id.\\n :return: id of the user.\\n If user_type is student, return student_id.\\n If user_type is teacher, return teacher_id.\\n \\\"\\\"\\\"\\n if user_type == UserType.STUDENT:\\n return student_id\\n elif user_type == UserType.TEACHER:\\n return teacher_id\\n else:\\n raise Exception(\\\"Invalid user.\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png", "document_node": "{\"id_\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95ee1c93-3fd8-4ccf-8c4c-76c63f5e6d68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"04fcb935e815a4801293eb7a2cf3895cc849cac7965b173b1c94fff6e473857e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"text\": \"Use the tool in VS Code\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\\n\\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\\n!before_user_type_selected.png\\n!after_user_type_selected_with_student.png\\n!after_user_type_selected_with_teacher.png\", \"start_char_idx\": 2, \"end_char_idx\": 417, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections.", "document_node": "{\"id_\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d27b2b3a-1f85-4708-b438-61936edefd56\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4cc9eeedc959aaa970d6346b761f25e5ade25ff26ab512556114ab76bebacf51\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"text\": \"FAQs\\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass EventType(str, Enum):\\n CORPORATE = \\\"corporate\\\"\\n PRIVATE = \\\"private\\\"\\n\\n\\nclass CorporateTheme(str, Enum):\\n SEMINAR = \\\"seminar\\\"\\n TEAM_BUILDING = \\\"team_building\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Multi-Layer Cascading Inputs\\\",\\n description=\\\"This is my tool with multi-layer cascading inputs\\\",\\n input_settings={\\n \\\"corporate_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[EventType.CORPORATE]),\\n \\\"seminar_location\\\": InputSetting(enabled_by=\\\"corporate_theme\\\", enabled_by_value=[CorporateTheme.SEMINAR]),\\n \\\"private_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[CorporateTheme.PRIVATE]),\\n }\\n)\\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\\"\\\"\\\"\\n pass\\n```\\nInputs will be enabled in a cascading way based on selections.\", \"start_char_idx\": 2, \"end_char_idx\": 1231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.", "document_node": "{\"id_\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67f40a0f-b078-4cc6-ab1e-949e061951a4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"253f1ef689b236779c4139c7b8a8596611a636413e760e9e65f92f24ba76df17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"text\": \"Creating a dynamic list tool input\\n\\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.\", \"start_char_idx\": 2, \"end_char_idx\": 507, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a289ce7d-3868-4476-b3c7-b04b6fffff8f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a62c53dbbe33681ff3ce43af54ec4c0c19328db473d060fb7b1f03598cffe84\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"text\": \"Prerequisites\\n\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 238, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a tool input with dynamic listing", "document_node": "{\"id_\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3cebe967-3b58-4f05-9acc-4b816ed796f9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1936ac053e77c95327c1bc7149e8bce2b7e1f7daf68aacac3294d6b850521487\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"text\": \"Create a tool input with dynamic listing\", \"start_char_idx\": 2, \"end_char_idx\": 42, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```", "document_node": "{\"id_\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e969bbff-b1eb-4490-b321-c72e7e471292\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbf6f556b19f8044dccf35bc5441bc853d43b758c6b30151e64513903af9ff2f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"text\": \"Create a list function\\n\\nTo enable dynamic listing, the tool author defines a request function with the following structure:\\n\\n- Type: Regular Python function, can be in tool file or separate file\\n- Input: Accepts parameters needed to fetch options\\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\\n - Required key:\\n - `value`: Internal option value passed to tool function\\n - Optional keys:\\n - `display_value`: Display text shown in dropdown (defaults to `value`)\\n - `hyperlink`: URL to open when option clicked\\n - `description`: Tooltip text on hover\\n\\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\\n\\n```python\\ndef my_list_func(prefix: str = \\\"\\\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\\n \\\"\\\"\\\"This is a dummy function to generate a list of items.\\n\\n :param prefix: prefix to add to each item.\\n :param size: number of items to generate.\\n :param kwargs: other parameters.\\n :return: a list of items. Each item is a dict with the following keys:\\n - value: for backend use. Required.\\n - display_value: for UI display. Optional.\\n - hyperlink: external link. Optional.\\n - description: information icon tip. Optional.\\n \\\"\\\"\\\"\\n import random\\n\\n words = [\\\"apple\\\", \\\"banana\\\", \\\"cherry\\\", \\\"date\\\", \\\"elderberry\\\", \\\"fig\\\", \\\"grape\\\", \\\"honeydew\\\", \\\"kiwi\\\", \\\"lemon\\\"]\\n result = []\\n for i in range(size):\\n random_word = f\\\"{random.choice(words)}{i}\\\"\\n cur_item = {\\n \\\"value\\\": random_word,\\n \\\"display_value\\\": f\\\"{prefix}_{random_word}\\\",\\n \\\"hyperlink\\\": f'https://www.bing.com/search?q={random_word}',\\n \\\"description\\\": f\\\"this is {i} item\\\",\\n }\\n result.append(cur_item)\\n\\n return result\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2026, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```", "document_node": "{\"id_\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0939118b-828a-4de3-98e9-776c2b8037ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"94f5070b41fbce81858222caf99a4153bd8580851d8f0acf8efaca5417fac9b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"text\": \"Configure a tool input with the list function\\n\\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\\n\\n- `DynamicList`:\\n - `function`: Path to the list function (module_name.function_name).\\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\\n- `is_multi_select`: Allow user to select multiple values. Default to false.\\n\\nSee tool_with_dynamic_list_input.py as an example.\\n\\n```python\\nfrom promptflow._core.tool import tool\\nfrom promptflow.entities import InputSetting, DynamicList\\n\\n\\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\\\"prefix\\\": \\\"input_prefix\\\"})\\ninput_settings = {\\n \\\"input_text\\\": InputSetting(\\n dynamic_list=dynamic_list_setting,\\n allow_manual_entry=True,\\n is_multi_select=True\\n )\\n}\\n\\n\\n@tool(\\n name=\\\"My Tool with Dynamic List Input\\\",\\n description=\\\"This is my tool with dynamic list input\\\",\\n input_settings=input_settings\\n)\\ndef my_tool(input_text: list, input_prefix: str) -> str:\\n return f\\\"Hello {input_prefix} {','.join(input_text)}\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1188, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.", "document_node": "{\"id_\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"241031e5-137a-4f62-8578-f9ae17176b94\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a22fc60300c108cc9ab2a273d80eab0db119f7e244396d4b27e13ac238703bf4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"text\": \"Use the tool in VS Code\\n\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\\n\\n```sh\\npip install my-tools-package>=0.0.8\\n```\\n\\n!dynamic list tool input options\\n!dynamic list tool input selected\\n\\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs", "document_node": "{\"id_\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52cf13ef-f7c7-4777-826e-3436e6fa10a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f155f38296df1d151acb9003db8e8b02ab7afa2138997d07168a8b16c93ecef3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure", "document_node": "{\"id_\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2670701d-65c8-4d71-93bf-9dc1af4ebd73\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e363a58b67cb6b64c1d4d39e722c563b324dcd45713d1ea775f43d875d420f54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"text\": \"I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\\n1. Clarify azure workspace triple \\\"subscription_id\\\", \\\"resource_group_name\\\", \\\"workspace_name\\\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\\n```python\\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \\\"\\\") -> List[Dict[str, str]]:\\n \\\"\\\"\\\"This is an example to show how to get Azure ML resource in tool input list function.\\n\\n :param subscription_id: Azure subscription id.\\n :param resource_group_name: Azure resource group name.\\n :param workspace_name: Azure ML workspace name.\\n :param prefix: prefix to add to each item.\\n \\\"\\\"\\\"\\n from azure.ai.ml import MLClient\\n from azure.identity import DefaultAzureCredential\\n\\n credential = DefaultAzureCredential()\\n credential.get_token(\\\"https://management.azure.com/.default\\\")\\n\\n ml_client = MLClient(\\n credential=credential,\\n subscription_id=subscription_id,\\n resource_group_name=resource_group_name,\\n workspace_name=workspace_name)\\n result = []\\n for ep in ml_client.online_endpoints.list():\\n hyperlink = (\\n f\\\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\\\"\\n f\\\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\\\"\\n f\\\"MachineLearningServices/workspaces/{workspace_name}\\\"\\n )\\n cur_item = {\\n \\\"value\\\": ep.name,\\n \\\"display_value\\\": f\\\"{prefix}_{ep.name}\\\",\\n # external link to jump to the endpoint page.\\n \\\"hyperlink\\\": hyperlink,\\n \\\"description\\\": f\\\"this is endpoint: {ep.name}\\\",\\n }\\n result.append(cur_item)\\n return result\\n```\\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\\n```sh\\naz login\\naz account set --subscription \\naz configure --defaults group= workspace=\\n```\\nInstall azure dependencies.\\n```sh\\npip install azure-ai-ml\\n```\\n```sh\\npip install my-tools-package[azure]>=0.0.8\\n```\\n!dynamic list function azure\", \"start_char_idx\": 2, \"end_char_idx\": 2312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.", "document_node": "{\"id_\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d769cf68-1d72-4689-8a9c-230f570e5cd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0b39012496db8b16e127cf6868f14f256d4316bf3b5682ae7057f2c021b207f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"text\": \"I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\\n\\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\\n\\n\\\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\\\"\\n\\nIf this occurs, follow these troubleshooting steps:\\n\\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.\", \"start_char_idx\": 2, \"end_char_idx\": 627, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.", "document_node": "{\"id_\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5e9e5a08-19ff-47b6-b70e-73ece4cea736\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"058be840749f87c3d4c1a9800979db634ce796b011d542b9d12e4b56f07dca74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"text\": \"Create and use your own custom strong type connection\\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections.", "document_node": "{\"id_\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c9f2fdac-08db-4edb-b3c6-a9088b3a70c8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"709f637c22d9b3f7a184550a7328629e9d8e7db1ca51f15982c8e50964ab1d43\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"text\": \"What is a Custom Strong Type Connection?\\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\\n\\n* Enhanced user experience - no need to manually enter connection keys.\\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\\n* Central location to view available keys and data types.\\n\\nFor other connections types, please refer to Connections.\", \"start_char_idx\": 2, \"end_char_idx\": 534, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fab38a19-7a14-4dbd-bab2-26cfcbc1a9bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cc0011738c8a85337bf926c06c918fa10b64f15184d623d4260ff99b5f86b18a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 230, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation.", "document_node": "{\"id_\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79cde2db-d429-4144-9fef-ecf1150f0b58\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef847fe7289c00e59ef01840ff34bece9995f06b5a69fc566387050ad2b15b33\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"text\": \"Create a custom strong type connection\\nFollow these steps to create a custom strong type connection:\\n\\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\\n\\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\\n\\n3. Document with docstrings explaining each key.\\n\\nFor example:\\n\\n```python\\nfrom promptflow.connections import CustomStrongTypeConnection\\nfrom promptflow.contracts.types import Secret\\n\\n\\nclass MyCustomConnection(CustomStrongTypeConnection):\\n \\\"\\\"\\\"My custom strong type connection.\\n\\n :param api_key: The api key.\\n :type api_key: Secret\\n :param api_base: The api base.\\n :type api_base: String\\n \\\"\\\"\\\"\\n api_key: Secret\\n api_base: str = \\\"This is a fake api base.\\\"\\n\\n```\\n\\nSee this example for a complete implementation.\", \"start_char_idx\": 2, \"end_char_idx\": 883, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:", "document_node": "{\"id_\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7387e95-ab5a-4a70-9c85-229d8acee9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3bbcd908601f7bcffce92d9d792b4b62c388bdf1d0303c84e7b579cf80efc9e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"text\": \"Use the connection in a flow\\nOnce you create a custom strong type connection, here are two ways to use it in your flows:\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow", "document_node": "{\"id_\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a3bd599a-a90a-4cbb-8037-6a13b6dd9c48\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ceaee00a227e4d995d979afa9533af34f51be8bf867a6b10088d37d2a5cca1c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"text\": \"With Package Tools:\\n\\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\\n\\n2. Develop a flow with custom tools. Please take this folder as an example.\\n\\n3. Create a custom strong type connection using one of the following methods:\\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\\n !create_custom_strong_type_connection_in_node_interface\\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\\n !create_custom_strong_type_connection_add_sign\\n - Click 'Create connection' plus sign in the Custom category.\\n !create_custom_strong_type_connection_in_custom_category \\n\\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\\n!custom_strong_type_connection_template\\n\\n5. Run the flow with the created custom strong type connection.\\n!use_custom_strong_type_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 955, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow", "document_node": "{\"id_\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"289b3241-2041-473c-bb43-232c26f7ad82\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b254e2ca79e4eb95b116cabc8863efc8ecc1d1d1e321860eef0efbe3513b0056\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"text\": \"With Script Tools:\\n\\n1. Develop a flow with python script tools. Please take this folder as an example.\\n\\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\\n !custom\\n\\n3. Run the flow with the created custom connection.\\n !use_custom_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```", "document_node": "{\"id_\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9ff5578c-d9c8-4600-8fd2-17be1c3a47bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f490870dcb22fb75d51c9cf96bd148cca6be0f1023c770decb6160254ac5c9a9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"text\": \"Local to cloud\\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\\n\\nPlease refer to Run prompt flow in Azure AI for more details.\\n\\nHere is an example command:\\n```\\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection\\\\data.jsonl --runtime test-compute\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 687, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQs", "document_node": "{\"id_\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec0fe169-0696-4b09-a1d4-5378bd80aae4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d1005131a9440a9cbe7be4a33e90326f422b8cce59ff3596ce0213b8cc1def9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.", "document_node": "{\"id_\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"696d6411-2b2e-4bae-88ec-df4715c2cb9c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986a6c2ecd58baffe38dd2942c83b8d33b868ae0a3a4a0a718ebc8c9dca4be53\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"text\": \"I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\\n\\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.\", \"start_char_idx\": 2, \"end_char_idx\": 317, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.", "document_node": "{\"id_\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7fa0f6dc-819e-4c87-8266-b5a9118914d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf6d565ab14197fe3684bddae73d8a73ef4207c61eb95247d99490c74d2d9e7e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"text\": \"Customizing an LLM tool\\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.", "document_node": "{\"id_\": \"60235800-c278-4134-8278-8e27e077672b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6223b1c5-30ec-4887-8019-87b5b08719b0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d4e6526ecfa0dc58bcb2f4ffe54c63f3992a85dd43b94c87bf3443adebc570f7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 103, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```", "document_node": "{\"id_\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6cf8beb9-6705-40b5-b808-781ec0951cc0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6803b97e70221d067b2043774c8b82ade81fdc957a43c72442bb8d905c46b6b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"text\": \"How to customize an LLM tool\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \\n\\nDevelop the tool code as in this example.\\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\\n\\n ```python\\n from jinja2 import Template\\n from promptflow import tool\\n from promptflow.connections import CustomConnection\\n from promptflow.contracts.types import PromptTemplate\\n\\n\\n @tool\\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\\n # Customize your own code to use the connection and prompt here.\\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\\n return rendered_prompt\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 968, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool", "document_node": "{\"id_\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"82bdb8e8-61f7-4a8f-a7f5-11b155607365\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2cf80cfa83e508b387c2eb96683e4e830b00ddaf57323fd26f63ac87e110d0ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"text\": \"Use the tool in VS Code\\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \\n- There is a node named \\\"my_custom_llm_tool\\\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \\n!use_my_custom_llm_tool\", \"start_char_idx\": 2, \"end_char_idx\": 410, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.", "document_node": "{\"id_\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cd195a3-97b4-4a97-82bd-c7d0e87ac685\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"112eaf9f4b6fd25ac3da2887c1935dc9baf039898a60471bebff81abb7c727ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"text\": \"Using file path as tool input\\n\\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\\n\\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 530, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.", "document_node": "{\"id_\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7568039d-4551-48fa-9297-ffb37efc43cf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"59cfa4561fe4293365a4c24a5b539aa6f87ff3607a91d2e043ab8601cec1281a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"text\": \"Prerequisites\\n\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using File Path as Package Tool Input", "document_node": "{\"id_\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"26a93b18-a56a-4cdb-929c-e140981115aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"53b32a0cdc76e7c0bbcc4dc06ef8c4956aa75f189a74a5c1c249410a75f556b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"text\": \"Using File Path as Package Tool Input\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool", "document_node": "{\"id_\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ce61fc15-2cdb-4a63-8987-134e03eb1b6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"281ae66cc1678a8b7eab1188b5b3f2f788aae682ca1ab5226c276b1438877cd8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"text\": \"How to create a package tool with file path input\\n\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\\n\\nAdd a `FilePath` input for your tool, like in this example.\\n\\n```python\\nimport importlib\\nfrom pathlib import Path\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 328, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath", "document_node": "{\"id_\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35d2d03c-9329-41d3-8daf-72bc10887d9b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86d6634bc35fe36a0c204adc8d64ddc65da434342731d413778eb0d1a15923f2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"text\": \"1. import the FilePath type\\nfrom promptflow.contracts.types import FilePath\", \"start_char_idx\": 2, \"end_char_idx\": 77, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.", "document_node": "{\"id_\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"333e8f14-0e51-4937-ba22-d6ecd8476ab9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0d3447a096e1bb3aa918cbd4757bea0a31384731c63c27e170e05d8cd82a188a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"text\": \"2. add a FilePath input for your tool method\\n@tool()\\ndef my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n\\n return new_module.hello(input_text) \\n```\\n\\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.\", \"start_char_idx\": 2, \"end_char_idx\": 427, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow", "document_node": "{\"id_\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7015a1ed-1b19-4e4b-9655-112c9e4e9d22\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"11825ea60a67309ba91e6cb42883fb16318dc1f0f387ff5c3698c09b6e09813f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"text\": \"Use tool with a file path input in VS Code extension\\n\\nFollow steps to build and install your tool package and use your tool from VS Code extension.\\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\\n\\n- There is a node named \\\"Tool_with_FilePath_Input\\\" with a `file_path` type input called `input_file`.\\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\\n\\n !use file path in flow\", \"start_char_idx\": 2, \"end_char_idx\": 487, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool", "document_node": "{\"id_\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd07b5eb-b7cc-42a6-ad08-b9576bd69f78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b1e8f36cab52aa8392c7af80f8578d3cccdb448d4aa2d78149acaa3a2054980c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"text\": \"Using File Path as Script Tool Input\\n\\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\\n\\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\\n ```python\\n import importlib\\n from pathlib import Path\\n from promptflow import tool\\n # 1. import the FilePath type\\n from promptflow.contracts.types import FilePath\\n\\n # 2. add a FilePath input for your tool method\\n @tool\\n def my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n \\n return new_module.hello(input_text) \\n ```\\n\\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\\n \\n !use file path in script tool\", \"start_char_idx\": 2, \"end_char_idx\": 1206, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "FAQ", "document_node": "{\"id_\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69991809-43a1-45e0-a7ed-543d5244ca8d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d69baeb0f63d28094f13c861f5b2704b30234f6ee523cbf5dbd3e40438e496a6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"text\": \"FAQ\", \"start_char_idx\": 2, \"end_char_idx\": 5, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.", "document_node": "{\"id_\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"412a990a-7993-48bb-8dae-a040894517aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef4ca3b0ff6e914f8fe374f18dc27d6bcf687fe1838060a4d95ee76c82ba5bb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"text\": \"What are some practical use cases for this feature?\\nThe `FilePath` input enables several useful workflows:\\n\\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\\n\\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.\", \"start_char_idx\": 2, \"end_char_idx\": 605, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.", "document_node": "{\"id_\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb38a3ca-cfe8-4dca-9b10-2466376b3300\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f471b7d48ccb913477b732b2d731cc7b4f592655595022c777f9e92c1ed4808\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"text\": \"Use streaming endpoints deployed from prompt flow\\n\\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\\n\\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\\n\\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\\n\\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.\", \"start_char_idx\": 2, \"end_char_idx\": 835, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png", "document_node": "{\"id_\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"706956f6-48c9-41a9-bb1c-da5a86236d6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3e1a444f441a07ab2df4fd50af04ae49bfb3b215a2bc6535f454b0306e8696e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"text\": \"Create a streaming enabled flow\\n\\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\\n\\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\\n ```jinja\\n {# Sample prompt template for LLM node #}\\n\\n system:\\n You are a helpful assistant.\\n\\n user:\\n {{question}}\\n ```\\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\\n ```python\\n from promptflow import tool\\n\\n # Sample code echo input by yield in Python tool node\\n\\n @tool\\n def my_python_tool(paragraph: str) -> str:\\n yield \\\"Echo: \\\"\\n for word in paragraph.split():\\n yield word + \\\" \\\"\\n ```\\n\\nIn this guide, we will use the \\\"Chat with Wikipedia\\\" sample flow as an example. This flow processes the user\\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\\n\\n!chat_wikipedia.png\", \"start_char_idx\": 2, \"end_char_idx\": 1372, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page.", "document_node": "{\"id_\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6c888e5e-8cc3-40a3-957c-c9490fb07aa7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf83dc0a7e113999480393c58b334373aff1e4fe2bdbed0ff974e231287e4ce7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"text\": \"Deploy the flow as an online endpoint\\n\\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\\n\\nFollow this guide to deploy your flow as an online endpoint.\\n\\n> [!NOTE]\\n> \\n> You can follow this document to deploy an online endpoint.\\n> Please deploy with runtime environment version later than version `20230816.v10`.\\n> You can check your runtime version and update runtime in the run time detail page.\", \"start_char_idx\": 2, \"end_char_idx\": 513, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:", "document_node": "{\"id_\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98c6ee2b-c91e-450b-964c-eb2654ba13bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0034781020f8eb762eb657bec70cf919844120f8791674e17ff9ec21750f2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"text\": \"Understand the streaming process\\n\\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\\n\\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\\n\\nTo understand the streaming process, consider the following steps:\\n\\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \\\"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\\\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\\n > [!NOTE]\\n > \\n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\\n \\n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\\n - If the `Accept` header specifies other media types, such as `text/html`:\\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\\n > Note: Please refer handle errors for details.\\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\\n\\nLet\\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\\n\\nThe overall process works as follows:\", \"start_char_idx\": 2, \"end_char_idx\": 2788, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response.", "document_node": "{\"id_\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddaf9efd-9ac9-4829-a54c-1648089d8d70\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"680ad8077e320e6e398a84f918cd7befe171f7bb12e18aee8904d3e2647b006f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"text\": \"0. The client sends a message to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Hello\\\",\\n \\\"chat_history\\\": []\\n}\\n```\\n> [!NOTE]\\n> \\n> The `Accept` header is set to `text/event-stream` to request a stream response.\", \"start_char_idx\": 2, \"end_char_idx\": 326, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.", "document_node": "{\"id_\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"821fdf27-98c6-43a4-8a2f-c784651596bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3aabc69a0ec2b4ab4cf0c35722875bb5c3a8751390b1eeafc540cc6ab9fd19d8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"text\": \"1. The server sends back the response in streaming mode.\\n\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Hello\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" How\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" assist\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" today\\\"}\\n\\ndata: {\\\"answer\\\": \\\" ?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\\n\\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\\n\\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\\n\\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.\", \"start_char_idx\": 2, \"end_char_idx\": 944, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"912d0e1f-a746-471c-a2a4-71fc2730e575\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d85b5ace9efc60427c9f464f9645bb0589929e638b563f9b7da4c5a5db69026\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Glad to know you!\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"Hello\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"answer\\\": \\\"Hello! How can I assist you today?\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 491, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```", "document_node": "{\"id_\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48347717-5e52-4331-8d92-6a7c54fe3d03\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554b3afb5397fc0a38ddb0164a88ae48a2e944d9d06f047d66f849aed83187aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Nice\\\"}\\n\\ndata: {\\\"answer\\\": \\\" to\\\"}\\n\\ndata: {\\\"answer\\\": \\\" know\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" too\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" there\\\"}\\n\\ndata: {\\\"answer\\\": \\\" anything\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" help\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" with\\\"}\\n\\ndata: {\\\"answer\\\": \\\"?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 607, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "4. The chat continues in a similar way.", "document_node": "{\"id_\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ac508813-a33c-4c2c-a3d1-773e79aef114\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6a748b536cb6dbb48de3c2fc76dfaee7b3ac7bb7e92983c1f6a60a2789577178\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"text\": \"4. The chat continues in a similar way.\", \"start_char_idx\": 2, \"end_char_idx\": 41, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user.", "document_node": "{\"id_\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3fd257bf-5cf8-4f99-bffc-e3bbc6f78390\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56eac9e90da9529ab6e04074e76b19d92a2b351f7e19b21d8973f970dc189c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"text\": \"Handle errors\\n\\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\\n\\nIf the response code is \\\"424 Model Error\\\", it means that the error is caused by the model\\u2019s code. The error response from a PromptFlow model always follows this format:\\n\\n```json\\n{\\n \\\"error\\\": {\\n \\\"code\\\": \\\"UserError\\\",\\n \\\"message\\\": \\\"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\\\",\\n }\\n}\\n```\\n* It is always a JSON dictionary with only one key \\\"error\\\" defined.\\n* The value for \\\"error\\\" is a dictionary, containing \\\"code\\\", \\\"message\\\".\\n* \\\"code\\\" defines the error category. Currently, it may be \\\"UserError\\\" for bad user inputs and \\\"SystemError\\\" for errors inside the service.\\n* \\\"message\\\" is a description of the error. It can be displayed to the end user.\", \"start_char_idx\": 2, \"end_char_idx\": 851, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to consume the server-sent events", "document_node": "{\"id_\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a6fd14f-f375-4da2-a24b-0cafcf1fddf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efe8860eada88de2417ef06be8a0990d2deea819d95cba2e97b9ca1a432e4c54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"text\": \"How to consume the server-sent events\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```", "document_node": "{\"id_\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dd27869b-15cf-42ca-b7e6-50aa08ba0d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7591010f02260b9174a1b2251dc262f58eb1a52ae423e651964800b13059af4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"text\": \"Consume using Python\\n\\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\\n\\n```bash\\npip install sseclient-py \\n```\\n\\nA sample usage would like:\\n\\n```python\\nimport requests \\nfrom sseclient import SSEClient \\nfrom requests.exceptions import HTTPError \\n\\ntry:\\n response = requests.post(url, json=body, headers=headers, stream=stream)\\n response.raise_for_status()\\n\\n content_type = response.headers.get('Content-Type')\\n if \\\"text/event-stream\\\" in content_type:\\n client = SSEClient(response)\\n for event in client.events():\\n # Handle event, i.e. print to stdout\\n else:\\n # Handle json response\\n\\nexcept HTTPError:\\n # Handle exceptions\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 792, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.", "document_node": "{\"id_\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"42e4799e-96c2-4780-a62c-923dc6c72ced\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ee102f88249caf546d0c0bdafd13b8f1a212f9d0775fc8151940e1fee75512c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"text\": \"Consume using JavaScript\\n\\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app", "document_node": "{\"id_\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c8f1f5f-4639-4ce0-a7e3-73399238b474\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3f1b447e5173f4bafc67db22b703f07422d77028dcf992b0553bd73fcd33c9b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"text\": \"A sample chat app using Python\\n\\nHere is a sample chat app written in Python.\\n(Click here to view the source code.)\\n\\n!chat_app\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.", "document_node": "{\"id_\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da359dbe-b196-465f-a58b-923cfa17400e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d36f27b1e6799c33c3a5f8115b7c7535edcea14977513849b56331f899eed90f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"text\": \"Advance usage - hybrid stream and non-stream flow output\\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \\u201cChat with Wikipedia\\u201d flow, you may want to get not only LLM\\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\\u2019s answer and non-stream URL list.\\n\\nIn the sample \\\"Chat With Wikipedia\\\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\\n\\n!chat_wikipedia_dual_output_center.png\\n\\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.\", \"start_char_idx\": 2, \"end_char_idx\": 805, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```", "document_node": "{\"id_\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"14f0a5dd-312e-4539-b900-5b291142a148\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ed2ed3f2b32332867a54f69c94b86e84eeedfce3c36e9a8010183b04b170e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"text\": \"0. The client sends a message to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\",\\n \\\"chat_history\\\": []\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d9f464-762e-4146-9352-9a808af3fde8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"02a6bf0f2539cc26435514fe55f4f59572376600cce1efc190c79b9fcd743123\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"text\": \"1. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\", \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 747, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"016b2ee8-acf4-4bdc-94c7-79463ab4a7db\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0aa2e2ac63ba13015313fe66dfbb8ec4203540014741ea1281303ddb606424c7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When did OpenAI announce GPT-4? How long is it between these two milestones?\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"url\\\": [\\n \\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\",\\n \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"\\n ],\\n \\\"answer\\\": \\\"ChatGPT was launched on November 30, 2022. \\\\n\\\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 833, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9fe0c1e9-3ca5-4c67-9d7c-bb987940b686\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29379ee510ab86ed5cf7ccd99fa4be6d0d1580d210182a61323bbbd0a9a44089\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \\\", \\\"https://en.wikipedia.org/w/index.php?search=Microsoft \\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Open\\\"}\\n\\ndata: {\\\"answer\\\": \\\"AI\\\"}\\n\\ndata: {\\\"answer\\\": \\\" released\\\"}\\n\\ndata: {\\\"answer\\\": \\\" G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"-\\\"}\\n\\ndata: {\\\"answer\\\": \\\"4\\\"}\\n\\ndata: {\\\"answer\\\": \\\" in\\\"}\\n\\ndata: {\\\"answer\\\": \\\" March\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" The\\\"}\\n\\ndata: {\\\"answer\\\": \\\" time\\\"}\\n\\ndata: {\\\"answer\\\": \\\" between\\\"}\\n\\ndata: {\\\"answer\\\": \\\" these\\\"}\\n\\ndata: {\\\"answer\\\": \\\" two\\\"}\\n\\ndata: {\\\"answer\\\": \\\" milestones\\\"}\\n\\ndata: {\\\"answer\\\": \\\" is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" approximately\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\" months\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1458, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::", "document_node": "{\"id_\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e02f01b8-6709-4920-9a8b-7e2c5e77be44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4fa90920b48a86b6763c89f59b0bddae5ecf0338d4fd85cb546c4cddc5864ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"text\": \"Execute flow as a function\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.", "document_node": "{\"id_\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ea36d385-1925-46e4-a5b7-e77f0f3cc6ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f1f3fd175e8d9c564036921a8f4759cac8cbcb556a37d3504935f460547b059\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"text\": \"Overview\\n\\nPromptflow allows you to load a flow and use it as a function in your code.\\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```", "document_node": "{\"id_\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fb1e5741-98bd-4b28-88dd-9c503d0421ef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f813adeab56a408bcb78b566016ee117476fd8356ae2dafe911f856ec3ca07ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"text\": \"Load an invoke the flow function\\n\\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\\nThen you can consume the flow object like a function by providing key-value arguments for it.\\n\\n```python\\nf = load_flow(\\\"../../examples/flows/standard/web-classification/\\\")\\nf(url=\\\"sample_url\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 330, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.", "document_node": "{\"id_\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"91e9d667-cfbc-4f4e-9240-09036f81dfc7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bce2f8b33b0e9c233454a16cc5975de252451fb6c45f3ad82274458c869fa0aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"text\": \"Config the flow with context\\n\\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)", "document_node": "{\"id_\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24e752d6-0029-4218-94ca-93a1465077b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d7195051357847107c3e1134dd358ec6063a42599855d090ebf34cb8707d0774\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"text\": \"Load flow as a function with in-memory connection override\\n\\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\\n\\n```python\\nfrom promptflow.entities import AzureOpenAIConnection\\n\\nconnection_obj = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=api_key,\\n api_base=api_base,\\n api_type=\\\"azure\\\",\\n api_version=api_version,\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```", "document_node": "{\"id_\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dde478bf-d6cb-43a8-b1a4-8d8d35f25e0f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ed8c2e142e9b716c24dadc03b5b75782fb42f44c8ed62da6f2131b6c418f2eb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"text\": \"no need to create the connection object.\\nf.context = FlowContext(\\n connections={\\\"classify_with_llm\\\": {\\\"connection\\\": connection_obj}}\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.", "document_node": "{\"id_\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a9785096-c148-4ec8-9a62-f6b9f80ef601\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1fcfc555a6a8a8a1950f5352afbdd252f325d853dbef81815bb12d212a5afe8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"text\": \"Local flow as a function with flow inputs override\\n\\nBy providing overrides, the original flow dag will be updated in execution time.\\n\\n```python\\nf.context = FlowContext(\\n # node \\\"fetch_text_content_from_url\\\" will take inputs from the following command instead of from flow input\\n overrides={\\\"nodes.fetch_text_content_from_url.inputs.url\\\": sample_url},\\n)\\n```\\n\\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.\", \"start_char_idx\": 2, \"end_char_idx\": 565, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\"", "document_node": "{\"id_\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6b681357-4cac-4553-b6a5-9df520eb030b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac1d912138d7d912b5c51e55b4e77d89d14ff84ee46ca9d1ee92acd7d9898b59\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"text\": \"Load flow as a function with streaming output\\n\\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\\n\\n```python\\nf = load_flow(source=\\\"../../examples/flows/chat/basic-chat/\\\")\\nf.context.streaming = True\\nresult = f(\\n chat_history=[\\n {\\n \\\"inputs\\\": {\\\"chat_input\\\": \\\"Hi\\\"},\\n \\\"outputs\\\": {\\\"chat_output\\\": \\\"Hello! How can I assist you today?\\\"},\\n }\\n ],\\n question=\\\"How are you?\\\",\\n)\\n\\n\\nanswer = \\\"\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage.", "document_node": "{\"id_\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bbbd143-9995-4367-939e-0c831eb263fe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2cfa7009b4997d3fde306b94dbf03de21819f05a14d0aaca580fc15eb62a26d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"text\": \"the result will be a generator, iterate it to get the result\\nfor r in result[\\\"answer\\\"]:\\n answer += r\\n\\n```\\n\\nReference our sample for usage.\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow", "document_node": "{\"id_\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07fb8988-8ef2-4450-aa41-2d21c42ff60a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a44b5c7aad060be11eb17db2bce6368d458f1e720941d3c50c807c071a6ce513\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"text\": \"Next steps\\n\\nLearn more about:\\n\\n- Flow as a function sample\\n- Deploy a flow\", \"start_char_idx\": 2, \"end_char_idx\": 76, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Frequency asked questions (FAQ)", "document_node": "{\"id_\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cb9f4a0f-e680-47fc-8f5d-5b223d51d083\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"743917481836b00908b09ff34a3d165a53a55bbd846807af36b7bb80a22a628c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"text\": \"Frequency asked questions (FAQ)\", \"start_char_idx\": 2, \"end_char_idx\": 33, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "General", "document_node": "{\"id_\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c597cc0b-d110-4165-8c96-53d36acef69d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"814d7155ef3529ff69b2385fcb080cd2c7b7fccacefb5d13c76ea02c151e3825\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"text\": \"General\", \"start_char_idx\": 2, \"end_char_idx\": 9, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.", "document_node": "{\"id_\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0fe4dd5d-e4c5-40ed-98e7-a044021dbf86\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1c42f40448725a9a0bd02a07496b82437c4fbad22447c717ff5a6f9ac9b220e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"text\": \"Stable vs experimental\\n\\nPrompt flow provides both stable and experimental features in the same SDK.\\n\\n|Feature status | Description | \\n|----------------|----------------|\\nStable features\\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.\", \"start_char_idx\": 2, \"end_char_idx\": 1143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details.", "document_node": "{\"id_\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bb3c750-f12d-4808-ab89-acf161dfd91e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6beadd06f30b207f672c997719c336539e7faf8ef36feaf44e40f65c1b4fa868\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"text\": \"OpenAI 1.x support\\nPlease use the following command to upgrade promptflow for openai 1.x support:\\n```\\npip install promptflow>=1.1.0\\npip install promptflow-tools>=1.0.0\\n```\\nNote that the command above will upgrade your openai package a version later than 1.0.0, \\nwhich may introduce breaking changes to custom tool code.\\n\\nReach OpenAI migration guide for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 369, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Troubleshooting", "document_node": "{\"id_\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e9acc577-1cbb-429e-970d-7c98723202ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af390d4c747d81b170f3d982c0a82884e61001ce8fe19ffbddc01b21b7d24626\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"text\": \"Troubleshooting\", \"start_char_idx\": 2, \"end_char_idx\": 17, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.", "document_node": "{\"id_\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6ba934f9-e5d6-4550-8a2f-0c6be54cd508\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8e9e6602be667f9cba044453ac50a9f815cf9662bbf038f534f5481bbbc3305b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"text\": \"Connection creation failed with StoreConnectionEncryptionKeyError\\n\\n```\\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\\n```\\n\\nThis error raised due to keyring can't find an available backend to store keys.\\nFor example macOS Keychain and Windows Credential Locker\\nare valid keyring backends.\\n\\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\\n`pip install keyrings.alt`\\n\\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.\", \"start_char_idx\": 2, \"end_char_idx\": 773, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.", "document_node": "{\"id_\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7499f3d-3746-45d8-bddc-7b8e7726100f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fb9686bc123c832e95558b925d4fb46cc4c621ce1ad04658d3092dc3e77c89\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"text\": \"Pf visualize show error: \\\"tcgetpgrp failed: Not a tty\\\"\\n\\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\\n\\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.\", \"start_char_idx\": 2, \"end_char_idx\": 367, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.", "document_node": "{\"id_\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0a6a1158-c713-4412-b59d-b85f18e89f0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"67bd1cc4115725959bb26b2e210e9bc34bdafb0f300364d873e67e7b6d1a203c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"text\": \"Installed tool not appearing in VSCode Extension tool list\\n\\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\\n\\n!VSCode Extension tool list\\n\\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\\n\\n1. Open the VSCode Extension window.\\n\\n2. Bring up the command palette by pressing \\\"Ctrl+Shift+P\\\".\\n\\n3. Type and select the \\\"Developer: Reload Webviews\\\" command. \\n\\n4. Wait a moment for the tool list refreshing.\\n\\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.\", \"start_char_idx\": 2, \"end_char_idx\": 716, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img", "document_node": "{\"id_\": \"98caef46-1716-47c8-8950-80296635edb6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8b886825-981c-4d7a-a456-b29e07a0f2c3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6b854d9357a3adff77eaf7bdce41cc3375c66d93c1da46c6f7928d8fc0c13fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"text\": \"Set logging level\\n\\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\\n\\n!img\\n\\nCompare to the serving logs with `WARNING` level:\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.", "document_node": "{\"id_\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"576f95f6-92d9-483f-822a-0ce9bf0bd395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45f83f4fb0b797a2d06fb8a2f9cfeb3c6c9008f2be62d661550b4b1311b1934a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"text\": \"Set environment variables\\n\\nCurrently, promptflow supports the following environment variables:\\n\\n**PF_WORKER_COUNT** \\n\\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\\n\\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\\n\\nWhen you modify the concurrency, please consider 2 points:\\n\\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\\n\\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\\n\\n```\\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\\n```\\nTPM: token per minute, capacity rate limit of your LLM endpoint\\n\\nduration_seconds: single flow run duration in seconds\\n\\ntoken_count: single flow run token count\\n\\n\\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\\n\\n**PF_BATCH_METHOD**\\n\\nValid for batch run only. Optional values: 'spawn', 'fork'. \\n\\n**spawn**\\n\\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\\n\\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\\n \\n**fork**\\n\\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\\n\\n2. The process starts faster as it doesn't need to reinitialize resources.\\n \\nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.\", \"start_char_idx\": 2, \"end_char_idx\": 2366, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```", "document_node": "{\"id_\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1bb38f65-df51-4e35-9339-b39205a74d42\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5ffb3a0055a7127117140f63d34e4ee966af213db99b4fa728c673465b4004c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"text\": \"You can configure environment variables in the following ways\\n\\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\\\"2\\\" PF_BATCH_METHOD=\\\"spawn\\\"```.\\n\\n2. If you are using SDK, you can specify environment variables when creating run. Example: \\n\\n``` python\\n pf = PFClient(\\n credential=credential,\\n subscription_id=\\\"\\\",\\n resource_group_name=\\\"\\\",\\n workspace_name=\\\"\\\",\\n )\\n\\n flow = \\\"web-classification\\\"\\n data = \\\"web-classification/data.jsonl\\\"\\n runtime = \\\"example-runtime-ci\\\"\\n\\n environment_variables = {\\\"PF_WORKER_COUNT\\\": \\\"2\\\", \\\"PF_BATCH_METHOD\\\": \\\"spawn\\\"}\\n\\n # create run\\n base_run = pf.run(\\n flow=flow,\\n data=data,\\n runtime=runtime,\\n environment_variables=environment_variables,\\n )\\n```\\n\\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\\n\\n``` yaml\\n name: flow_name\\n display_name: display_name\\n flow: flow_folder\\n data: data_file\\n column_mapping:\\n customer_info: \\n history: \\n environment_variables:\\n PF_WORKER_COUNT: \\\"2\\\"\\n PF_BATCH_METHOD: \\\"spawn\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1240, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it.", "document_node": "{\"id_\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2d12cb4e-9982-46b1-8020-5a397a5c70ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27490f9ccc0a4ef12bcef73484eb8f041e969282c05eff50bb23a31b4394ca93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"text\": \"Initialize and test a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, customer can initialize a flow and test it.\", \"start_char_idx\": 2, \"end_char_idx\": 208, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow.", "document_node": "{\"id_\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"223ae55b-31d0-4a3f-a845-e2cbb48d2174\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a987c0ab8aa00ab20a17431c70079e376558edd598e742211a1b6d6323108503\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"text\": \"Initialize flow\\n\\nCreating a flow folder with code/prompts and yaml definitions of the flow.\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a5ad4e4-84f4-4725-8096-3096c1ce097f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9d2f6bed32465c8afd0d71f4ff8109ac9daee9f05c58a3b9afe2016bca66aa5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"text\": \"Initialize flow from scratch\\n\\nPromptflow can create three types of flow folder:\\n- standard: Basic structure of flow folder.\\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 525, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a flow\npf flow init --flow", "document_node": "{\"id_\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a66b4440-7ab7-4a0a-8e3e-cf53ce0da183\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c55a21ae37e2c8abc954550c17e8d4ae89c001cbd51afbdf6250026ab8111cd7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"text\": \"Create a flow\\npf flow init --flow\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder", "document_node": "{\"id_\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3979a8ce-fe87-4ab5-b144-4b734aa35c25\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"184c77063135f92e2154daff06d061bfd4a0dc94f3d65875b712e2986daca02a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"text\": \"Create a chat flow\\npf flow init --flow --type chat\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse VS Code explorer pane > directory icon > right click > the \\\"New flow in this directory\\\" action. Follow the popped out dialog to initialize your flow in the target folder.\\n!img\\n\\nAlternatively, you can use the \\\"Create new flow\\\" action on the prompt flow pane > quick access section to create a new flow\\n!img\\n\\n:::\\n\\n::::\\n\\n\\nStructure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n!init_flow_folder\", \"start_char_idx\": 2, \"end_char_idx\": 847, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash", "document_node": "{\"id_\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15bc22d5-c272-430d-b04a-79cfe65f18fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"66785e16e82b7ffa50adb19068670cd130f8b3dc6ab081a908061308b313ce3c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"text\": \"Create from existing code\\n\\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 414, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files", "document_node": "{\"id_\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8a15b7b7-5711-4d86-917f-4fc2036c6027\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6c03c3df69e37b72e57a0a75ca81f10041bf1c7f5b9b1a3c8506b13f6aa43f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"text\": \"Create a flow in existing folder\\npf flow init --flow --entry --function --prompt-template =\\n```\\n\\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\\n\\n!init_output\\n\\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\\n\\n!init_files\", \"start_char_idx\": 2, \"end_char_idx\": 396, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.", "document_node": "{\"id_\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95cd3374-d155-4f86-b29d-fb4bf987e22b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9422effd2aaeb2748e289c5baf349916d999564c3179e620610f11eb42dd375e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"text\": \"Test a flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::", "document_node": "{\"id_\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2aafc740-6302-4dbf-a42d-ee1dea0c6ebf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"446896168b129cd5539cb3091ff4073483ad34e324321c181d6a0901e0abd70a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"text\": \"Visual editor on the VS Code for prompt flow.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \\\"Visual editor\\\" action. Use it to open the Visual editor with GUI support.\\n\\n!img\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 300, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ee0cc84-3f98-42e6-8a67-fbdee3586ccc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b83ff835b3a805eb03482d718707c0e686d12752df5f55dce13fd7e2fcaf50a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"text\": \"Test flow\\n\\nCustomer can use CLI or VS Code extension to test the flow.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\npf flow test --flow", "document_node": "{\"id_\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd5cefe7-28c9-4bf0-9fc6-8b3609de5b5a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"229f3f16a238a91b31c7e47ac2e91406ec163f09cd791edd3eb594209a03c0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"text\": \"Test flow\\npf flow test --flow\", \"start_char_idx\": 2, \"end_char_idx\": 31, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"49dd7bd1-552d-40a9-8f03-e533f0e08d54\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ddf2f5446188a40b24a32a024a1b0544334ba529ecba86dda4f49f1d4be2129\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"text\": \"Test flow with specified variant\\npf flow test --flow --variant '${.}'\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 577, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d1ad1393-927d-41d6-8139-7e599f0f06e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"89b24a887590553199b9ee0c1b9fc51a85ab692e6db323dbdcd22c2255e9a892\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 702, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash", "document_node": "{\"id_\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4eb28b8-dc68-48de-87fe-746453fa405a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"125b62feb2a0b81e72c1bbb54a25128fe0ef760e2cf21a4de506ac04bc14cc5e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"text\": \"Test a single node in the flow\\n\\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nCustomer can execute this command to test the flow.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 337, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7b80b991-92a3-41ea-a747-36708cbc9dd2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68553f1861f970ef898e05440d384d9c431f59f1b74bb863b93bba6b233fac22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"text\": \"Test flow node\\npf flow test --flow --node \\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 419, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"18f1adbf-ecc3-4b53-8418-89329a15ce5e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd07e53bbd4061d9ac9e11b6f588c17761eb7b3a19c7444a286fc89370fc0325\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"text\": \"Test not iun the flow\\ninputs = {: } # The inputs of the node.\\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 533, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash", "document_node": "{\"id_\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd754830-349c-4e11-a781-bb24512461e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3d66f9f55eb3364c049a109ae76e0f366d5b39f746f9732b4cc63961d184d1b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"text\": \"Test with interactive mode\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 234, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1dfba4cb-27ff-46d4-9f89-6e585c66e7af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"15964bbe99b83f7830453b5a2e5113f3bef996cda9aa8ef777a98643873a429f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"text\": \"Chat in the flow\\npf flow test --flow --interactive\\n```\\n\\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\\n\\nUsing this chat flow to show how to use interactive mode.\\n\\n!chat\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\\n\\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe flow result will be streamed in the terminal as shown below.\\n\\n!streaming_output\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 1162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::", "document_node": "{\"id_\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf5960ff-bb2a-46e1-91ec-56aca552ecbd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c8c2606c9b6fb9f5472c28e53817c83a807118199ca561ac221ee50d994050db\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nfor item in flow_result[\\\"\\\"]:\\n print(item)\\n```\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 169, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bdc16d88-1916-4304-a6f7-440c9efca1ca\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82e4d3ca19496b8c5d4386adfd56d7eaa8cc032e8c7c141ef4c7e886eef46caa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"text\": \"Debug a single node in the flow\\n\\nCustomer can debug a single python node in VScode by the extension.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 374, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\n- Add conditional control to a flow", "document_node": "{\"id_\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d5caefb5-8563-48c6-814b-b513309e144c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86f72212dd70181df51676601190b6b412486d8aeeaeca9885371345ea964535\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"text\": \"Next steps\\n\\n- Add conditional control to a flow\", \"start_char_idx\": 2, \"end_char_idx\": 49, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::", "document_node": "{\"id_\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c679040-3627-4e7a-8599-ae144332c763\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bc0144e32aa85d7452b6071e6e0ac610d0995a2640ead996bc906162475a7c77\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"text\": \"Manage connections\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\\n\\n:::{note}\\nTo use azureml workspace connection locally, refer to this guide.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 422, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.", "document_node": "{\"id_\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c4ff6b8-fe67-4ec7-9eea-a84769ed42fa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9fc840fdb46639dfa7f2c0c5525c7397a8b717192d4e4fd05796d2a5443e72d7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"text\": \"Connection types\\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\\n\\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 502, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash", "document_node": "{\"id_\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48897b0d-44af-4c0a-8411-f4048af44ce9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"849f9eedece63c894efdd476e9e1bb3dde2e5c55044c6a782b51bf3bb4b48b7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"text\": \"Create a connection\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: azure_open_ai_connection\\ntype: azure_open_ai\\napi_key: \\\"\\\"\\napi_base: \\\"https://.openai.azure.com/\\\"\\napi_type: \\\"azure\\\"\\napi_version: \\\"2023-03-15-preview\\\"\\n```\\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\\nname: custom_connection\\ntype: custom\\nconfigs:\\n endpoint: \\\"\\\"\\n other_config: \\\"other_value\\\"\\nsecrets: # required\\n my_key: \\\"\\\"\\n```\\nAfter preparing the yaml file, use the CLI command below to create them:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1078, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key=", "document_node": "{\"id_\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"87222c5e-4f77-4b93-8d69-d5f7af5f06f3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0e4402c636bd9dd666a5652039e3f48b4f98339d223f75428020f237415d64fa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"text\": \"Override keys with --set to avoid yaml file changes\\npf connection create -f --set api_key=\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection", "document_node": "{\"id_\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"415192cd-10f2-45df-b939-9de5ea5c8ee0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d9fac2f2493f493188f30ca653a58bf91bee6219703e2123ffaafdb01a378519\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"text\": \"Create the custom connection\\npf connection create -f --set configs.endpoint= secrets.my_key=\\n```\\nThe expected result is as follows if the connection created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5ac1b34a-f365-46b2-af27-98df27795edb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d704aa2ec218d1b1acc8c01252d81cd49440df151dd5ec4a92ccf0fbb54a87ff\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)", "document_node": "{\"id_\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddfa8c7c-cdd4-4073-ad8c-34534a20b49a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a7db8e137fd4c7c07d1f4ae406b7ee0b2aad89be313957c12e3d2c9efdf5538\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"text\": \"Initialize an AzureOpenAIConnection object\\nconnection = AzureOpenAIConnection(\\n name=\\\"my_azure_open_ai_connection\\\", \\n api_key=\\\"\\\", \\n api_base=\\\"\\\"\\n api_version=\\\"2023-03-15-preview\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 193, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)", "document_node": "{\"id_\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86e2c793-3cb8-4ec7-bc7d-44576f1a8170\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0a0e5bcab0cc6aca9da6836e7fd11cd9442b42270019b48113f33540fb9d8d40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"text\": \"Create the connection, note that api_key will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)", "document_node": "{\"id_\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a130569c-c523-4a83-be04-b4706f124c1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"011cb400a1083e76cc32cc921b1a71a76b18dde3df75f4b224a9b9e1d9434f90\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"text\": \"Initialize a custom connection object\\nconnection = CustomConnection(\\n name=\\\"my_custom_connection\\\", \\n # Secrets is a required field for custom connection\\n secrets={\\\"my_key\\\": \\\"\\\"},\\n configs={\\\"endpoint\\\": \\\"\\\", \\\"other_config\\\": \\\"other_value\\\"}\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e783be9d-0148-44a5-ab4f-dd0523ac8334\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"751dfc933b0e96e74f8ce306a449da30d196af0146bd2bf18261f765194c180f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"text\": \"Create the connection, note that all secret values will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \\\"+\\\" icon on the top right of it and follow the popped out instructions to create your new connection.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 463, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash", "document_node": "{\"id_\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e85cc25f-3348-406f-af8a-2754d2339ac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ff8b3d46333114d6aa64b7572fc631715461e38af0f2ddf90f5bd6ceefe0483\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"text\": \"Update a connection\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe commands below show how to update existing connections with new values:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'", "document_node": "{\"id_\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3abffd3b-ed39-4218-bce7-5becbd65db6c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74e7f2cb5f8df53cffe2b8bf20c9755b3e0cd188ab67d8f242d74e36cd2d5773\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"text\": \"Update an azure open ai connection with a new api base\\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python", "document_node": "{\"id_\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"50207311-5c91-4251-a254-720a7b40926a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"73a939ef359ad24d3ddae75e1280b2e91a6cca8a37caa45b3b798800a099da3a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"text\": \"Update a custom connection\\npf connection update -n my_custom_connection --set configs.other_config='new_value'\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nThe code snippet below shows how to update existing connections with new values:\\n```python\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)", "document_node": "{\"id_\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c76ef7e2-4457-4746-aa80-44d36f3e679d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e529352592a59587b997627812a31f186d8aad0960591837b21f31fcca158ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"text\": \"Update an azure open ai connection with a new api base\\nconnection = pf.connections.get(name=\\\"my_azure_open_ai_connection\\\")\\nconnection.api_base = \\\"new_value\\\"\\nconnection.api_key = \\\"\\\" # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\", \"start_char_idx\": 2, \"end_char_idx\": 312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"63dd3856-a79f-497b-a8e0-aa61b446d692\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5025c879a00830a327e4ec3f23a86b5566cb9fa543823d37bbe40e4c5cec352\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"text\": \"Update a custom connection\\nconnection = pf.connections.get(name=\\\"my_custom_connection\\\")\\nconnection.configs[\\\"other_config\\\"] = \\\"new_value\\\"\\nconnection.secrets = {\\\"key1\\\": \\\"val1\\\"} # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f6d9da7-52eb-4abf-8a2e-a927ee735541\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d3ea86a42100eb1fe366be6811c4eeaac9dfb41944fb89ba80ff1b66f248a615\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"text\": \"List connections\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\\n```bash\\npf connection list\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 415, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f51d9a42-127f-4ea9-9792-e149e8a38a7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02057374-00f7-431d-9da0-156db1202852\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5700cd94662430caae88bb657f1bca9ea785a2616bc964557182744191e247dc\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"text\": \"List and print connections\\nconnection_list = pf.connections.list()\\nfor connection in connection_list:\\n print(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 191, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9829818d-2389-4b7a-b824-87ff80e4e5bc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50527ec74e94bfc190f0dbf98b325f1f2e187c5ac5ec86d7a09dfee41c9592c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"text\": \"Delete a connection\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nDelete a connection with the following command:\\n```bash\\npf connection delete -n \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nDelete a connection with the following code snippet:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 279, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e31a56f7-dfde-4662-a545-e3382f5d2395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"09e1d45a-e995-4845-9819-61a50a7e3fcc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62a9b42d19dc3a2618a57b3123475f3e48b57c65cef1d43fd9918153ffb040ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"text\": \"Delete the connection with specific name\\nclient.connections.delete(name=\\\"my_custom_connection\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI.", "document_node": "{\"id_\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"345ef80f-a13b-4a7a-a85c-fcb140faf879\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d5386667d921191043732d28b80d2062181886d4c8ab54880eaed2e9a80f6a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"text\": \"Next steps\\n- Reach more detail about connection concepts.\\n- Try the connection samples.\\n- Consume connections from Azure AI.\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run", "document_node": "{\"id_\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb5ce587-ed3b-4933-90a2-cd69af33569a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f5704af61f5056221d2e79bc09b64b5866186f2a9d92c1973198f7ad601ff0c2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"text\": \"Manage runs\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \\n\\nIn general:\\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\\n\\nLet's take a look at the following topics:\\n\\n- Manage runs\\n - Create a run\\n - Get a run\\n - Show run details\\n - Show run metrics\\n - Visualize a run\\n - List runs\\n - Update a run\\n - Archive a run\\n - Restore a run\", \"start_char_idx\": 2, \"end_char_idx\": 668, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash", "document_node": "{\"id_\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2f925fe9-ce2c-4854-b77b-13180f4a0960\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2128e989c9a49e28690407060252f2ed66ab45c3e599f65cfcd28e80fa2cdde9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"text\": \"Create a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nTo create a run against bulk inputs, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../web_classification\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n url: \\\"${data.url}\\\"\\nvariant: ${summarize_text_content.variant_0}\\n```\\n\\nTo create a run against existing run, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../classification_accuracy_evaluation\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n groundtruth: \\\"${data.answer}\\\"\\n prediction: \\\"${run.outputs.category}\\\"\\nrun: \\n```\\n\\nReference here for detailed information for column mapping.\\nYou can find additional information about flow yaml schema in Run YAML Schema.\\n\\nAfter preparing the yaml file, use the CLI command below to create them:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 940, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create the flow run\npf run create -f", "document_node": "{\"id_\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e8f49d4b-09cb-4725-b400-3e6a57e6f756\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1f5b6613de87d844d48e200c9b9c9059eeec4f91a3db91eecb7cdab65d19814c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"text\": \"create the flow run\\npf run create -f\", \"start_char_idx\": 2, \"end_char_idx\": 38, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run", "document_node": "{\"id_\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69b30e6f-ae04-4662-b070-0d2f621ebefe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4633642239f0ea5e8c401ec55305ae8b31da7edc8a8b8d683eb99d6fe9106406\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"text\": \"create the flow run and stream output\\npf run create -f --stream\\n```\\n\\nThe expected result is as follows if the run is created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import Run\", \"start_char_idx\": 2, \"end_char_idx\": 409, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7d2a225f-8af5-476f-89c9-80c92eeb0470\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad254fb5c3bfa9051eb14e7387114c2a5c1c76bbb931108fe180d2bb19b7054\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)", "document_node": "{\"id_\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd6f0ea0-d59d-4713-9cd0-ba3eb0e65942\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48b09a6ad917a748e77953d709c4a0363847b171256aca5776de986d2a3403cf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"text\": \"Initialize an Run object\\nrun = Run( \\n flow=\\\"\\\",\\n # run flow against local data or existing run, only one of data & run can be specified. \\n data=\\\"\\\",\\n run=\\\"\\\",\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n variant=\\\"${summarize_text_content.variant_0}\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 264, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d537c095-e0b4-4578-bd01-a7a6ecfdaa26\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbdad1ed5255e045338bc1ee9997c8440345b0219f5f7c566599525647199619\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"text\": \"Create the run\\nresult = pf.runs.create_or_update(run)\\nprint(result)\\n\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 301, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aa7fb66b-5547-4381-8445-5b889fbd750d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"670696330b3c61d1dd01ad6a0443001a2420bde7594a46160f3014ae731abb72\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"text\": \"Get a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet a run in CLI with JSON format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 233, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f49dcc8e-cb73-4d39-9315-4850fbf8574f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fd00d1e-3ff5-4e22-b9f3-6b9035a840f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b3bab73b36683da5ccd33b89ba1de7fe035ca591a43a5a2a2343c5ff007be74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"text\": \"Get and print the run\\nrun = pf.runs.get(name=\\\"\\\")\\nprint(run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate", "document_node": "{\"id_\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"056517ad-77d6-4567-bd42-784249e7099e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac8e842a7b5768c58167cad9416d5c3a46f31c4ca4b60615181298880853c1d0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"text\": \"Show run details\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run details with TABLE format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run details with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nfrom tabulate import tabulate\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9528494c-6fe6-435e-8311-638da383dc41\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f68960fd-78ed-4eb5-9c21-41c88a20f97c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"49293e272e5907c1688626b39b858b564c40e0a463d3bbf18bc4ae7e5851ac17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"text\": \"Get and print the run-details\\nrun_details = pf.runs.get_details(name=\\\"\\\")\\nprint(tabulate(details.head(max_results), headers=\\\"keys\\\", tablefmt=\\\"grid\\\"))\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 216, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json", "document_node": "{\"id_\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bafa7c22-c619-45f8-9c0d-e8fca3753d61\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cf1e0bec2347094aba059e8ccaea3ab4d987ec96d413c8f38bc4c038be5a274\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"text\": \"Show run metrics\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run show-metrics --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run metrics with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nimport json\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f36b0ba6-a935-419f-be60-64b86bfcd0af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::", "document_node": "{\"id_\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0acc4e77-5cef-41d4-8dd5-2d3ee287789a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305909b84d1072067287befc0fbbab8cd1a5653d9336a909d32a9bacc21cf2d3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"text\": \"Get and print the run-metrics\\nrun_details = pf.runs.get_metrics(name=\\\"\\\")\\nprint(json.dumps(metrics, indent=4))\\n```\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f1c9b212-965b-41d9-808f-a859cf2bcf64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f7b2bd2c6d767e2394c033cf46a8b2756409e7a2158e17b96e651c5c5ff13ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"text\": \"Visualize a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nVisualize run in browser.\\n\\n```bash\\npf run visualize --name \\n```\\n\\nA browser will open and display run outputs.\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nVisualize run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 286, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"83ebe531-d05f-4a18-b981-b032188e1a91\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::", "document_node": "{\"id_\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d47b6b-d1bb-4135-99c6-94e0587982d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2dd6d3b52ab30d4dda87b658da7a20d31661a20e90afadbfd6ba9ee96ada3ab0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"text\": \"Visualize the run\\nclient.runs.visualize(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \\\"visualize\\\" button on the top-right to visualize the local runs.\\n\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 341, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8cd0973b-621c-4ac5-ab7b-b761e9464968\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b8464057578b5ba3ccb4ef18e6269f22e0645221ea15c48138dba649196cbf3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"text\": \"List runs\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nList runs with JSON format.\\n\\n```bash\\npf run list\\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 215, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"689f1a61-021c-4d09-8f36-af664354d82a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::", "document_node": "{\"id_\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"62d58288-30a7-403a-ae78-e96ab797625a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8658b0ec41f3abc61402be75b54a6e1ae936ba8728c5ca85595757a37f92b1c8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"text\": \"list runs\\nruns = pf.runs.list()\\nprint(runs)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a882a5b2-ae70-4e60-8dec-44ab6aa5de17\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a99bfa43094dbfe48415d7cfa311835783debea8e004b3617c06d72e8a9f14e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"text\": \"Update a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run update --name --set display_name=new_display_name\\n```\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUpdate run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 269, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d622f6da-925e-4499-b2bc-e6c1b88a7764\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::", "document_node": "{\"id_\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"12a0c48d-32ba-458c-b98b-5ce685fbecd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f180fb15fb20882c0f33f6f5bcf0d9c267d70b9f7fd04436d7be890c0ae9fbb1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"text\": \"Get and print the run-metrics\\nrun = pf.runs.update(name=\\\"\\\", display_name=\\\"new_display_name\\\")\\nprint(run)\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 118, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0e1f5935-4d6c-42a3-9b09-3da53cf5dbc6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a226c721d83c0dc240f7149e90068679e1185971e0efc5cd3750d3688f7be6f4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"text\": \"Archive a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nArchive the run so it won't show in run list results.\\n\\n```bash\\npf run archive --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nArchive with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 251, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a01b3d2-3028-4464-8113-24d35a37127c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67df2602-4039-4fc6-b097-7d52f3ab80d3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3105c8e1a55b304a67ffac4d9723179527619bd43eb7fb30ba9e8be0057b447\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"text\": \"archive a run\\nclient.runs.archive(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 110, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"73b1be5c-105b-4991-a760-2cdc603ef913\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3515081b130b61184610302211a976ed86236d28529ea29de4e4062eeed2b6fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"text\": \"Restore a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nRestore an archived run so it can show in run list results.\\n\\n```bash\\npf run restore --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nRestore with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 257, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a6b2dca-a015-4f46-8e4c-8f420c172cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::", "document_node": "{\"id_\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52013f35-f7b9-4ead-99a3-ce4a40a7b0a0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9ff0a8fc8da582672ffd435dede081836c045e4c0bfad1bc35f00dd9ddd90b1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"text\": \"restore a run\\nclient.runs.restore(name=\\\"\\\")\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data.", "document_node": "{\"id_\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3f073cc8-dbd7-404a-b000-72bbff9558a2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b0fe45f7655286420820fe760ab00a37e2f5838b36fb118fc4ec5008b5f86060\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"text\": \"Process image in flow\\nPromptFlow defines a contract to represent image data.\", \"start_char_idx\": 2, \"end_char_idx\": 78, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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.", "document_node": "{\"id_\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5efdffd0-715a-49b8-b862-8c06fd69756a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9037551182ef68ff8573f23d59d51ab0122c07bd8b67195a7927188e9cdfc942\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"text\": \"Data class\\n`promptflow.contracts.multimedia.Image`\\nImage 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.\", \"start_char_idx\": 2, \"end_char_idx\": 338, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image.", "document_node": "{\"id_\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"be5c5590-cc2c-471d-9a1a-9d6ba6654b4a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9cfbe119c907229fa7c21d195971a302e523c3d4fd165529faabcbe96bc04923\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"text\": \"Data type in flow input\\nSet the type of flow input to `image` and promptflow will treat it as an image.\", \"start_char_idx\": 2, \"end_char_idx\": 105, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.", "document_node": "{\"id_\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbc9ce4b-d4c9-4821-9508-f9923f82ce76\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae851217d3af4fca9c7ef102cf46a9c6e94d378388c1ce5ec771632962af0989\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"text\": \"Reference image in prompt template\\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario.", "document_node": "{\"id_\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25990bbe-88b7-404e-b27b-dba038a55cab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c110c9ce51caed1fd070c097b462340c73e276069cb4bf96a739d73cba30a06e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"text\": \"Serialization/Deserialization\\nPromptflow uses a special dict to represent image.\\n`{\\\"data:image/;\\\": \\\"\\\"}`\\n\\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\\n- `` is the image serialized representation, there are 3 supported types:\\n\\n - url\\n\\n It can point to a public accessable web url. E.g.\\n\\n {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\\\"}\\n - base64\\n\\n It can be the base64 encoding of the image. E.g.\\n\\n {\\\"data:image/png;base64\\\": \\\"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\\\"}\\n\\n - path\\n\\n 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.\\n\\n {\\\"data:image/png;path\\\": \\\"./my-image.png\\\"}\\n\\nPlease note that `path` representation is not supported in Deployment scenario.\", \"start_char_idx\": 2, \"end_char_idx\": 1496, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```", "document_node": "{\"id_\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19d77c76-c58e-4192-90d8-c49cb217b41c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92124ab99bd3cf499149ae86dd3f01b6d954639f457778cad90613e5049ac45e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"text\": \"Batch Input data\\nBatch input data containing image can be of 2 formats:\\n1. 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.\\n ```json\\n {\\\"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\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/404.png\\\"}}\\n ```\\n2. 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:\\n ```\\n BatchInputFolder\\n |----input.jsonl\\n |----image1.png\\n |----image2.png\\n ```\\n Content of `input.jsonl`\\n ```json\\n {\\\"question\\\": \\\"How many colors are there in the image?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image1.png\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image2.png\\\"}}\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1318, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.", "document_node": "{\"id_\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13b2e87c-864e-48d7-a298-aa0405987f0e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"79570951aa402f8b5f4e3c3b8c54c819fcb929b1a4d6de04a5f0a9e9b9d305c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"text\": \"Quick Start\\n\\nThis guide will walk you through the fist step using of prompt flow code-first experience.\\n\\n**Prerequisite** - To make the most of this tutorial, you'll need:\\n\\n- Know how to program with Python :)\\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\\n\\n\\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\\n- Setup your python environment to run prompt flow\\n- Clone a sample flow & understand what's a flow\\n- Understand how to edit the flow using visual editor or yaml\\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.\", \"start_char_idx\": 2, \"end_char_idx\": 623, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash", "document_node": "{\"id_\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cccf3a8-00b2-4eea-925d-a6d165906fb2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"587ff0eab41d0c313506a1b48bba59f016d271767a7706df438d3b94b95d70f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"text\": \"Set up your dev environment\\n\\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\\n```bash\\nconda create --name pf python=3.9\\nconda activate pf\\n```\\n\\n2. Install `promptflow` and `promptflow-tools`.\\n```sh\\npip install promptflow promptflow-tools\\n```\\n\\n3. Check the installation.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 457, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```", "document_node": "{\"id_\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"38042954-c5f8-49e2-ad7a-8dd102cb9e4b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c85e37e9cb465346ff4d30d688adc584079228796b48af10d2c71ceb2335616\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"text\": \"should print promptflow version, e.g. \\\"0.1.0b3\\\"\\npf -v\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 59, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.", "document_node": "{\"id_\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2ba34ea4-ae4b-4056-b39f-5912c5a0fa64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a4f168922683539a819e5ea2cd78f563c61381d82a343207632856d7d161254\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"text\": \"Understand what's a flow\\n\\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```", "document_node": "{\"id_\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a05adf23-8e8c-45aa-b2af-53428b3c4ab3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb849308243c212f582c607ade0182cb365a92c8d404b5e5fb594118d2c07357\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"text\": \"Get the flow sample\\n\\nClone the sample repo and check flows in folder examples/flows.\\n\\n```bash\\ngit clone https://github.com/microsoft/promptflow.git\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79a0a064-1fcf-426a-8548-0cbbbe034e7c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44b92b2fd3a018be8e3053359e32a4423d9b6474f12db760ac37fe43281bbb32\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"text\": \"Understand flow directory\\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\\n\\n```bash\\ncd promptflow/examples/flows/standard/web-classification\\n```\\n\\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n\\n!flow_dir\\n\\nIn order to run this specific flow, you need to install its requirements first.\\n\\n```sh\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 946, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section.", "document_node": "{\"id_\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e7c432c7-346e-4c79-9d66-4944eaab2398\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"585f3bbe83645c654d93216d5a9b001b56b9ef008cf9693379ade54887ec1a42\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"text\": \"Understand the flow yaml\\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\\n\\n!flow_dag\\n\\nThis graph is rendered by VS Code extension which will be introduced in the next section.\", \"start_char_idx\": 2, \"end_char_idx\": 274, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode", "document_node": "{\"id_\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5d15c1f0-b882-4e0f-a58e-b1f1e5f9e228\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81e60ad7a846d99edaec0186774aa9ebb0110cb857c56d2328868b7e0fa46711\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"text\": \"Using VS Code Extension to visualize the flow\\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\\n\\n1. Prerequisites for VS Code extension.\\n - Install latest stable version of VS Code\\n - Install VS Code Python extension\\n\\n2. Install Prompt flow for VS Code extension\\n\\n3. Select python interpreter\\n\\n !vscode\\n !vscode\\n\\n\\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\\n !vscode\", \"start_char_idx\": 2, \"end_char_idx\": 497, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Develop and test your flow", "document_node": "{\"id_\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"720071dc-66cc-4ed4-9b59-173a870d30ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"714af737aa81a554f0df7e22fd1b79dcdd62a3fbdd515c290cad89305d189339\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"text\": \"Develop and test your flow\", \"start_char_idx\": 2, \"end_char_idx\": 28, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow.", "document_node": "{\"id_\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"488319e9-bfcd-4afc-a6dc-d9dc568d8222\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4280e9afda0f6e201ad8aa74bea5818f07bfee49457a332e90c7775a5b169aea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"text\": \"How to edit the flow\\n\\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\\ninputs:\\n url:\\n type: string\\n # change the default value of input url here\\n default: https://play.google.com/store/apps/details?id=com.twitter.android\\n...\\n```\\nSee more details of this topic in Develop a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 532, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection", "document_node": "{\"id_\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aba5bfb1-05ae-468c-be62-0a1a07c9d628\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4304344b05c441a6eb462f8c791c8d9a04408b2ff3ebeb03674bafdc081a41e3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"text\": \"Create necessary connections\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n\\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\\n\\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\\n\\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nFirstly we need a connection yaml file `connection.yaml`:\\n\\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: azure_open_ai\\napi_key: \\napi_base: \\napi_type: azure\\napi_version: \\n```\\n\\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: open_ai\\napi_key: \\\"\\\"\\norganization: \\\"\\\" # optional\\n```\\nThen we can use CLI command to create the connection.\\n\\n```sh\\npf connection create -f connection.yaml\\n```\\n\\nMore command details can be found in CLI reference.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nIn SDK, connections can be created and managed with `PFClient`.\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection\", \"start_char_idx\": 2, \"end_char_idx\": 1802, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections.", "document_node": "{\"id_\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c529519b-67a4-4ca2-82d6-88e7699c8200\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ed7487a25062f53a7b930269186ea7f0954012d2027cad99b2715db455927b9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"text\": \"PFClient can help manage your runs and connections.\\npf = PFClient()\\n\\ntry:\\n conn_name = \\\"open_ai_connection\\\"\\n conn = pf.connections.get(name=conn_name)\\n print(\\\"using existing connection\\\")\\nexcept:\\n connection = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=\\\"\\\",\\n api_base=\\\"\\\",\\n api_type=\\\"azure\\\",\\n api_version=\\\"\\\",\\n )\\n\\n # use this if you have an existing OpenAI account\\n # from promptflow.entities import OpenAIConnection\\n # connection = OpenAIConnection(\\n # name=conn_name,\\n # api_key=\\\"\\\",\\n # )\\n\\n conn = pf.connections.create_or_update(connection)\\n print(\\\"successfully created connection\\\")\\n\\nprint(conn)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n\\n\\n1. Click the promptflow icon to enter promptflow control panel\\n\\n !vsc_add_connection\\n\\n2. Create your connection.\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n\\n:::\\n\\n::::\\n\\nLearn more on more actions like delete connection in: Manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 1030, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name", "document_node": "{\"id_\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6e2090d9-29f8-4fce-90c8-b577f114642b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d5a26e33893b1d820d9201b77c301375b1bac6e1020962824c2eab192622768\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"text\": \"Test the flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\n\\nAssuming you are in working directory `promptflow/examples/flows/standard/`\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nChange the default input to the value you want to test.\\n\\n!q_0\\n\\n```sh\\npf flow test --flow web-classification # \\\"web-classification\\\" is the directory name\\n```\\n\\n!flow-test-output-cli\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow/node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient()\\n\\nflow_path = \\\"web-classification\\\" # \\\"web-classification\\\" is the directory name\", \"start_char_idx\": 2, \"end_char_idx\": 793, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")", "document_node": "{\"id_\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00d12aa2-2fba-4094-ba89-2b5100553cbf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2eb38f79e9511a30a686a54c0c9328d8f27b6533f88da23af285578f841f825c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"text\": \"Test flow\\nflow_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\", \\\"answer\\\": \\\"Channel\\\", \\\"evidence\\\": \\\"Url\\\"} # The inputs of the flow.\\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\", \"start_char_idx\": 2, \"end_char_idx\": 243, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow.", "document_node": "{\"id_\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c8481bc3-2fa6-4f9e-bbcf-50426bc810c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2f184b383bba7eaa575f03d802ddda93cb93c77c0c9aa1a1b18fc95da8c0b85c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"text\": \"Test node in the flow\\nnode_name = \\\"fetch_text_content_from_url\\\" # The node name in the flow.\\nnode_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\"} # The inputs of the node.\\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\n!Flow test outputs\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse the code lens action on the top of the yaml editor to trigger flow test\\n!dag_yaml_flow_test\\n\\n\\nClick the run flow button on the top of the visual editor to trigger flow test.\\n!visual_editor_flow_test\\n:::\\n\\n::::\\n\\nSee more details of this topic in Initialize and test a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 666, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.", "document_node": "{\"id_\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cd6ec34-2ff3-4ef6-a334-5325a792d6be\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f922b16e03e9c87176794882ed1ecdce02c8480f87787e537137efa790a4d7b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"text\": \"Next steps\\n\\nLearn more on how to:\\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\\n- Deploy a flow: how to deploy the flow as a web app.\\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\\n\\nAnd you can also check our examples, especially:\\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.\", \"start_char_idx\": 2, \"end_char_idx\": 1011, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow.", "document_node": "{\"id_\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"30c31860-92f8-47c4-8143-ed8a60bef754\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6456b9cffe36ddc31ab56d1934541df995350acf57169caef45954e5432ef45\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"text\": \"Use column mapping\\n\\nIn this document, we will introduce how to map inputs with column mapping when running a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 116, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column.", "document_node": "{\"id_\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f7f2a950-7877-4434-9ad9-91c026212720\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7463dd8b40dd4febe72041037b50febcc30e9f037aa9038b0930a4ce8aed2b8a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"text\": \"Column mapping introduction\\n\\nColumn mapping is a mapping from flow input name to specified values.\\nIf specified, the flow will be executed with provided value for specified inputs.\\nThe following types of values in column mapping are supported:\\n\\n- `${data.}` to reference from your test dataset.\\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\\n- `STATIC_VALUE` to create static value for all lines for specified column.\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow", "document_node": "{\"id_\": \"54218434-a846-4601-b725-da39ad450bac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3b22908e-2696-4ca0-ab38-15c436581212\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a65e49af872870820c0aa44888d4bec1d26b74f685c8f8f6b0e82e567dcaa2e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"text\": \"Flow inputs override priority\\n\\nFlow input values are overridden according to the following priority:\\n\\n\\\"specified in column mapping\\\" > \\\"default value\\\" > \\\"same name column in provided data\\\".\\n\\nFor example, if we have a flow with following inputs:\\n\\n```yaml\\ninputs:\\n input1:\\n type: string\\n default: \\\"default_val1\\\"\\n input2:\\n type: string\\n default: \\\"default_val2\\\"\\n input3:\\n type: string\\n input4:\\n type: string\\n...\\n```\\n\\nAnd the flow will return each inputs in outputs.\\n\\nWith the following data\\n\\n```json\\n{\\\"input3\\\": \\\"val3_in_data\\\", \\\"input4\\\": \\\"val4_in_data\\\"}\\n```\\n\\nAnd use the following YAML to run\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: path/to/flow\", \"start_char_idx\": 2, \"end_char_idx\": 718, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data", "document_node": "{\"id_\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85ecd312-c7aa-48ca-89cb-4d16ac411b2d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"924fbc0961d3d7d9de76a32f571c6ff05573670311e7c52c2288ea2aa20c43da\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"text\": \"my_flow has default value val2 for key2\\ndata: path/to/data\", \"start_char_idx\": 2, \"end_char_idx\": 60, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data.", "document_node": "{\"id_\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e74459fb-15d7-4a3d-ae93-101437c2bd75\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"698d6a2dc2865dae75ed798ff334ae53e59410e15e656c44e2cedc8fd117bb6b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"text\": \"my_data has column key3 with value val3\\ncolumn_mapping:\\n input1: \\\"val1_in_column_mapping\\\"\\n input3: ${data.input3}\\n```\\n\\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\\n\\n!column_mapping_details\\n\\n- Input \\\"input1\\\" has value \\\"val1_in_column_mapping\\\" since it's specified as constance in `column_mapping`.\\n- Input \\\"input2\\\" has value \\\"default_val2\\\" since it used default value in flow dag.\\n- Input \\\"input3\\\" has value \\\"val3_in_data\\\" since it's specified as data reference in `column_mapping`.\\n- Input \\\"input4\\\" has value \\\"val4_in_data\\\" since it has same name column in provided data.\", \"start_char_idx\": 2, \"end_char_idx\": 657, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.", "document_node": "{\"id_\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0745af7e-ec63-49a3-8913-9ce62b2de223\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27e034e72d909f547920ecb5bfea736f1ab1e439d826daa7d913ef75116ce89f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"text\": \"Set global configs\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\\n\\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.\", \"start_char_idx\": 2, \"end_char_idx\": 541, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```", "document_node": "{\"id_\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c304b195-516b-47e0-900a-fbad4496fde3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"88f72ac96bfaa0b271618b9c8f66bcc2de5d37e2a9e6d26e26bcc54921321ebd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"text\": \"Set config\\n```shell\\npf config set =\\n```\\nFor example:\\n```shell\\npf config set connection.provider=\\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 200, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```", "document_node": "{\"id_\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a73d8903-c78a-4ef8-8591-c5fe90893d80\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"264d76e266c35e6a139d87b304d20aaf5393fe43b13ece323df3ff74b235e613\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"text\": \"Show config\\nThe following command will get all configs and show them as json format:\\n```shell\\npf config show\\n```\\nAfter running the above config set command, show command will return the following result:\\n```json\\n{\\n \\\"connection\\\": {\\n \\\"provider\\\": \\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n }\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 358, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values.", "document_node": "{\"id_\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b56e2759-71a4-4872-aac3-59ee3a94a1f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1761fcf18f56ea37a32fff9d05bc05935c4d26f821644ab355085b65b7d1a304\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"text\": \"Supported configs\\nThe connection provider, default to \\\"local\\\". There are 3 possible provider values.\", \"start_char_idx\": 2, \"end_char_idx\": 102, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.", "document_node": "{\"id_\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e66b553-7359-4b97-afdc-8f38395dc946\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09bfdea661db0c1bc689c1372efa2a0820d2f05cbcaebd5f56fb3e0542f42848\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"text\": \"local\\nSet connection provider to local with `connection.provider=local`.\\n\\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.\", \"start_char_idx\": 2, \"end_char_idx\": 252, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::", "document_node": "{\"id_\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07f8fe3d-7333-4508-a442-6d98e99eef0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"91bd5a95942ac400dca084af0a6320249f0b2e643d08b786e6608b413a891d7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"text\": \"full azure machine learning workspace resource id\\nSet connection provider to a specific workspace with:\\n```\\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\n```\\n\\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\\n\\n:::{note}\\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 701, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.", "document_node": "{\"id_\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ca93927-7b13-4533-a448-2c9898d0a1c7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d2ac101a7dad86028f9b2b6cc6cb864cf7a91da7f23df582bc7a081651a09b19\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"text\": \"azureml\\nIn addition to the full resource id, you can designate the connection provider as \\\"azureml\\\" with `connection.provider=azureml`. In this case,\\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\\n\\nThe expected format of the config file is as follows:\\n```json\\n{\\n \\\"workspace_name\\\": \\\"\\\",\\n \\\"resource_group\\\": \\\"\\\",\\n \\\"subscription_id\\\": \\\"\\\"\\n}\\n\\n```\\n\\n> \\ud83d\\udca1 Tips\\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.\", \"start_char_idx\": 2, \"end_char_idx\": 763, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first.", "document_node": "{\"id_\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f4b19098-b649-49fb-ba3a-256c50177102\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f1d3fdba7aff41e34517c387405f43a643cc9bdc273d4608b5b84dabc5b8561e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"text\": \"Tune prompts using variants\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nTo better understand this part, please read Quick start and Run and evaluate a flow first.\", \"start_char_idx\": 2, \"end_char_idx\": 236, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence.", "document_node": "{\"id_\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"596d09b8-71b6-4d61-8033-f700c9e6e166\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f86c56fcebb73fc409192845f5a32aeb1bdc75a71e12db269ab09c95f37353ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"text\": \"What is variant and why should we care\\n\\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\\u2019s accuracy, diversity, or coherence.\", \"start_char_idx\": 2, \"end_char_idx\": 400, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\"", "document_node": "{\"id_\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"042639b8-edf6-4943-b574-68f37cb821e5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3891ba9e1032a54312c877719e8bc6185815a78c2077ee309de42674e31602f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"text\": \"Create a run with different variant node\\n\\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\\n\\n\\n```yaml\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n...\\nnode_variants:\\n summarize_text_content:\\n default_variant_id: variant_0\\n variants:\\n variant_0:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '128'\\n temperature: '0.2'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n variant_1:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content__variant_1.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '256'\\n temperature: '0.3'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n```\\n\\nYou can check the whole flow definition in flow.dag.yaml.\\n\\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \\nAssuming you are in working directory `/examples/flows/standard`\\n\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote we pass `--variant` to specify which variant of the node should be running.\\n\\n```sh\\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\\n```\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient() # get a promptflow client\\nflow = \\\"web-classification\\\"\\ndata= \\\"web-classification/data.jsonl\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 2080, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.", "document_node": "{\"id_\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8551fee8-9698-4a4e-a6c2-68ad0c5ad168\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4b1feb415aba95a00177594f96a7c35009b9cc3a06174dfdc0557050e30fdb0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"text\": \"use the variant1 of the summarize_text_content node.\\nvariant_run = pf.run(\\n flow=flow,\\n data=data,\\n variant=\\\"${summarize_text_content.variant_1}\\\", # use variant 1.\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n)\\n\\npf.stream(variant_run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n!img\\n!img\\n:::\\n\\n::::\\n\\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.\", \"start_char_idx\": 2, \"end_char_idx\": 465, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI", "document_node": "{\"id_\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98e9445a-c154-4bc3-9647-d54e3459349d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2fbfc42e24e9a1378f4fafdbd1334335ff983a743a84920e31777f80cf4f2921\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"text\": \"Next steps\\n\\nLearn more about:\\n- Run and evaluate a flow\\n- Deploy a flow\\n- Prompt flow in Azure AI\", \"start_char_idx\": 2, \"end_char_idx\": 99, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} \ No newline at end of file From 8c46b97d4419b54546e24c7a7f86d8a984ec81c8 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 14:12:51 +0800 Subject: [PATCH 027/112] add config --- examples/test_data_gen/config.ini.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/test_data_gen/config.ini.example b/examples/test_data_gen/config.ini.example index 0969c3dd6d1..25226e10e67 100644 --- a/examples/test_data_gen/config.ini.example +++ b/examples/test_data_gen/config.ini.example @@ -1,8 +1,8 @@ ; config.ini ; This is a sample configuration file -[DEFAULT] -; The DEFAULT section provides default values for all other sections. +[COMMON] +; The COMMON section provides common values for all other sections. ; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. ; However, if you wish to bypass the document split process, simply provide the 'document_node_file', which is a JSONL file. ; When all these parameters are configured, the system will primarily use the 'document_node_file' From 042133f8087130a24703f94e39779d0fd5335a44 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 15:21:05 +0800 Subject: [PATCH 028/112] refine the structure --- .../gen_test_data}/__init__.py | 0 .../gen_test_data/gen_test_data/config.ini | 34 +++++++++++++++ .../gen_test_data}/config.ini.example | 4 +- .../gen_test_data}/document-nodes-test.jsonl | 0 .../generate_test_data_flow}/flow.dag.yaml | 40 +++++++++--------- .../generate_debug_info.py | 24 +++++------ .../generate_suggested_answer.py} | 6 +-- .../generate_suggested_answer_prompt.jinja2} | 0 .../generate_test_data_flow}/requirements.txt | 0 .../seed_question_prompt.jinja2 | 0 .../generate_test_data_flow}/utils.py | 7 +-- .../validate_and_generate_seed_question.py | 0 .../validate_and_generate_test_question.py | 0 .../validate_question_prompt.jinja2 | 0 .../validate_suggested_answer.py} | 20 ++++----- .../validate_suggested_answer_prompt.jinja2} | 14 +++--- .../validate_test_question.py | 0 .../validate_text_trunk_prompt.jinja2 | 0 .../gen_test_data}/requirements.txt | 0 .../gen_test_data}/requirements_cloud.txt | 0 .../gen_test_data}/run.py | 8 ++-- .../gen_test_data}/utils/__init__.py | 0 .../gen_test_data}/utils/common.py | 0 .../gen_test_data}/utils/components.py | 0 .../gen_test_data}/utils/constants.py | 4 +- .../gen_test_data/test_docs/test_doc.docx | Bin 0 -> 16235 bytes .../Jan-30-2024-15-16-20/document_nodes.jsonl | 1 + .../Jan-30-2024-15-17-41/document_nodes.jsonl | 1 + .../Jan-30-2024-15-17-41/test-data.jsonl | 1 + 29 files changed, 101 insertions(+), 63 deletions(-) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/__init__.py (100%) create mode 100644 examples/gen_test_data/gen_test_data/config.ini rename examples/{test_data_gen => gen_test_data/gen_test_data}/config.ini.example (92%) rename examples/{test_data_gen => gen_test_data/gen_test_data}/document-nodes-test.jsonl (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/flow.dag.yaml (78%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/generate_debug_info.py (75%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py => gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py} (76%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 => gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2} (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/requirements.txt (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/seed_question_prompt.jinja2 (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/utils.py (94%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/validate_and_generate_seed_question.py (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/validate_and_generate_test_question.py (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/validate_question_prompt.jinja2 (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py => gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py} (56%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 => gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2} (81%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/validate_test_question.py (100%) rename examples/{test_data_gen/test_data_gen/construct_test_data_flow => gen_test_data/gen_test_data/generate_test_data_flow}/validate_text_trunk_prompt.jinja2 (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/requirements.txt (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/requirements_cloud.txt (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/run.py (95%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/utils/__init__.py (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/utils/common.py (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/utils/components.py (100%) rename examples/{test_data_gen/test_data_gen => gen_test_data/gen_test_data}/utils/constants.py (85%) create mode 100644 examples/gen_test_data/test_docs/test_doc.docx create mode 100644 examples/test_data_gen/output/Jan-30-2024-15-16-20/document_nodes.jsonl create mode 100644 examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl create mode 100644 examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl diff --git a/examples/test_data_gen/test_data_gen/__init__.py b/examples/gen_test_data/gen_test_data/__init__.py similarity index 100% rename from examples/test_data_gen/test_data_gen/__init__.py rename to examples/gen_test_data/gen_test_data/__init__.py diff --git a/examples/gen_test_data/gen_test_data/config.ini b/examples/gen_test_data/gen_test_data/config.ini new file mode 100644 index 00000000000..90b16322e03 --- /dev/null +++ b/examples/gen_test_data/gen_test_data/config.ini @@ -0,0 +1,34 @@ +; config.ini +; This is a sample configuration file + +[COMMON] +; The COMMON section provides common values for all other sections. +; Configure both 'documents_folder' and 'document_chunk_size' if you require document splitting. +; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. +; When all these parameters are configured, the system will primarily use the 'document_nodes_file' +documents_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\gen_test_data\test_docs" +document_chunk_size = 1024 +document_nodes_file = "" + +; Test data gen flow configs +flow_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\gen_test_data\gen_test_data\generate_test_data_flow" ; There is must one flow.dag.yaml file under this folder as entry +connection_name = "open-ai-connection" + + +[LOCAL] +; This section is for local test data generation related configuration. +output_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\test_data_gen\output" +flow_batch_run_size = 10 + + +[PIPELINE] +; This section is for cloud test data generation related configuration. +subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" +resource_group = "promptflow" +workspace_name = "yaopfeus" +aml_cluster = "cpu-cluster" + +; Parallel run step configs +prs_instance_count = 2 +prs_mini_batch_size = "10kb" +prs_max_concurrency_per_instance = 10 diff --git a/examples/test_data_gen/config.ini.example b/examples/gen_test_data/gen_test_data/config.ini.example similarity index 92% rename from examples/test_data_gen/config.ini.example rename to examples/gen_test_data/gen_test_data/config.ini.example index 25226e10e67..edcaca489da 100644 --- a/examples/test_data_gen/config.ini.example +++ b/examples/gen_test_data/gen_test_data/config.ini.example @@ -6,9 +6,9 @@ ; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. ; However, if you wish to bypass the document split process, simply provide the 'document_node_file', which is a JSONL file. ; When all these parameters are configured, the system will primarily use the 'document_node_file' -document_folder = "" +documents_folder = "" document_chunk_size = 1024 -document_node_file = "" +document_nodes_file = "" ; Test data gen flow configs flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry diff --git a/examples/test_data_gen/document-nodes-test.jsonl b/examples/gen_test_data/gen_test_data/document-nodes-test.jsonl similarity index 100% rename from examples/test_data_gen/document-nodes-test.jsonl rename to examples/gen_test_data/gen_test_data/document-nodes-test.jsonl diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml similarity index 78% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 520bb19636a..b2c589839b8 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -12,9 +12,9 @@ outputs: question: type: string reference: ${validate_test_question.output} - ground_truth: + suggested_answer: type: string - reference: ${validate_ground_truth.output.ground_truth} + reference: ${validate_suggested_answer.output.suggested_answer} debug_info: type: string reference: ${generate_debug_info.output} @@ -43,11 +43,11 @@ nodes: inputs: context: ${inputs.text_chunk} use_variants: false -- name: generate_ground_truth_prompt +- name: generate_suggested_answer_prompt type: prompt source: type: code - path: generate_ground_truth_prompt.jinja2 + path: generate_suggested_answer_prompt.jinja2 inputs: context: ${inputs.text_chunk} question: ${validate_test_question.output} @@ -59,7 +59,7 @@ nodes: path: validate_and_generate_seed_question.py inputs: connection: open-ai-connection - model: gpt-4-1106-preview + model: gpt-4 validate_text_trunk_prompt: ${validate_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} context: ${inputs.text_chunk} @@ -71,7 +71,7 @@ nodes: path: validate_and_generate_test_question.py inputs: connection: open-ai-connection - model: gpt-4-1106-preview + model: gpt-4 validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output.question} response_format: "" @@ -91,20 +91,20 @@ nodes: path: validate_test_question.py inputs: connection: open-ai-connection - model: gpt-4-1106-preview + model: gpt-4 question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} use_variants: false -- name: generate_ground_truth +- name: generate_suggested_answer type: python source: type: code - path: generate_ground_truth.py + path: generate_suggested_answer.py inputs: connection: open-ai-connection context: ${inputs.text_chunk} - generate_ground_truth_prompt: ${generate_ground_truth_prompt.output} - model: gpt-4-1106-preview + generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} + model: gpt-4 question: ${validate_test_question.output} use_variants: false - name: generate_debug_info @@ -118,21 +118,21 @@ nodes: text_meta: ${inputs.text_meta} validate_and_generate_seed_question_output: ${validate_and_generate_seed_question.output} validate_and_generate_test_question_output: ${validate_and_generate_test_question.output} - validate_ground_truth_output: ${validate_ground_truth.output} -- name: validate_ground_truth_prompt + validate_suggested_answer_output: ${validate_suggested_answer.output} +- name: validate_suggested_answer_prompt type: prompt source: type: code - path: validate_ground_truth_prompt.jinja2 + path: validate_suggested_answer_prompt.jinja2 inputs: - ground_truth: ${generate_ground_truth.output} -- name: validate_ground_truth + suggested_answer: ${generate_suggested_answer.output} +- name: validate_suggested_answer type: python source: type: code - path: validate_ground_truth.py + path: validate_suggested_answer.py inputs: connection: open-ai-connection - model: gpt-4-1106-preview - ground_truth: ${generate_ground_truth.output} - validate_ground_truth_prompt: ${validate_ground_truth_prompt.output} + model: gpt-4 + suggested_answer: ${generate_suggested_answer.output} + validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py similarity index 75% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_debug_info.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index aea76b6ac4e..647af7bbc3b 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -13,18 +13,18 @@ def my_python_tool( text_meta: dict = None, validate_and_generate_seed_question_output: dict = None, validate_and_generate_test_question_output: dict = None, - validate_ground_truth_output: ValidationResult = None, + validate_suggested_answer_output: ValidationResult = None, ) -> dict: text_trunk_validation_res = validate_and_generate_seed_question_output["validation_res"] generated_seed_question = validate_and_generate_seed_question_output["question"] seed_question_validation_res = validate_and_generate_test_question_output["validation_res"] - generated_ground_truth = validate_ground_truth_output["ground_truth"] - ground_truth_validation_res = validate_ground_truth_output["validation_res"] + generated_suggested_answer = validate_suggested_answer_output["suggested_answer"] + suggested_answer_validation_res = validate_suggested_answer_output["validation_res"] - is_generation_success = generated_ground_truth != "" + is_generation_success = generated_suggested_answer != "" is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None is_seed_question_valid = seed_question_validation_res.pass_validation if seed_question_validation_res else None - is_ground_truth_valid = ground_truth_validation_res.pass_validation if ground_truth_validation_res else None + is_suggested_answer_valid = suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None failed_step = "" failed_reason = "" @@ -35,9 +35,9 @@ def my_python_tool( elif is_seed_question_valid is False: failed_step = ValidateObj.QUESTION failed_reason = seed_question_validation_res.reason_if_failed - elif is_ground_truth_valid is False: + elif is_suggested_answer_valid is False: failed_step = ValidateObj.GROUND_TRUTH - failed_reason = ground_truth_validation_res.reason_if_failed + failed_reason = suggested_answer_validation_res.reason_if_failed return { "question_type": question_type, @@ -63,11 +63,11 @@ def my_python_tool( else None, }, # "test_question": {}, # placeholder for evolved questions like multi-context, reasoning, etc. - "ground_truth": { - "generated_ground_truth": generated_ground_truth, - "pass_validation": is_ground_truth_valid, - "reason_if_failed": ground_truth_validation_res.reason_if_failed - if is_ground_truth_valid is False + "suggested_answer": { + "generated_suggested_answer": generated_suggested_answer, + "pass_validation": is_suggested_answer_valid, + "reason_if_failed": suggested_answer_validation_res.reason_if_failed + if is_suggested_answer_valid is False else None, }, }, diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py similarity index 76% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index 5e0d9f28486..e83cd7d0124 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -7,12 +7,12 @@ @tool -def generate_ground_truth( +def generate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, question: str, context: str, - generate_ground_truth_prompt: str, + generate_suggested_answer_prompt: str, ): """ Generates a ground truth based on the given prompts and context information. @@ -21,6 +21,6 @@ def generate_ground_truth( str: The generated ground truth. """ if question and context: - return llm_call(connection, model, generate_ground_truth_prompt) + return llm_call(connection, model, generate_suggested_answer_prompt) else: return "" diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/generate_ground_truth_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/requirements.txt b/examples/gen_test_data/gen_test_data/generate_test_data_flow/requirements.txt similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/requirements.txt rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/requirements.txt diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py similarity index 94% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index cebaa5d24dd..4766849bff7 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -22,7 +22,7 @@ class QuestionType: class ValidateObj: QUESTION = "question" TEXT_TRUNK = "text_trunk" - GROUND_TRUTH = "ground_truth" + SUGGESTED_ANSWER = "suggested_answer" class ResponseFormat: @@ -42,6 +42,7 @@ class ErrorMsg: def llm_call(connection, model, prompt, response_format=ResponseFormat.TEXT): response_format = "json_object" if response_format.lower() == "json" else response_format + prompt = f"{{% raw %}}{prompt}{{% endraw %}}" if isinstance(connection, AzureOpenAIConnection): return aoai_chat( connection=connection, prompt=prompt, deployment_name=model, response_format={"type": response_format} @@ -59,10 +60,10 @@ def get_question_type(testset_distribution) -> str: return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) -def get_ground_truth_validation_res(connection, model, prompt, ground_truth: str): +def get_suggested_answer_validation_res(connection, model, prompt, suggested_answer: str): rsp = llm_call(connection, model, prompt) return retrieve_verdict_and_print_reason( - rsp=rsp, validate_obj_name=ValidateObj.GROUND_TRUTH, validate_obj=ground_truth + rsp=rsp, validate_obj_name=ValidateObj.SUGGESTED_ANSWER, validate_obj=suggested_answer ) diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py similarity index 56% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index dc1498772b6..008c0705457 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -1,6 +1,6 @@ from typing import Union -from utils import ErrorMsg, get_ground_truth_validation_res +from utils import ErrorMsg, get_suggested_answer_validation_res from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -10,11 +10,11 @@ # Adding type to arguments and return value will help the system show the types properly # Please update the function name/signature per need @tool -def validate_ground_truth( +def validate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, - ground_truth: str, - validate_ground_truth_prompt: str, + suggested_answer: str, + validate_suggested_answer_prompt: str, ): """ 1. Validates the given ground truth. @@ -22,15 +22,15 @@ def validate_ground_truth( Returns: dict: The generated ground truth and its validation result. """ - if not ground_truth: - return {"ground_truth": "", "validation_res": None} + if not suggested_answer: + return {"suggested_answer": "", "validation_res": None} - validation_res = get_ground_truth_validation_res(connection, model, validate_ground_truth_prompt, ground_truth) + validation_res = get_suggested_answer_validation_res(connection, model, validate_suggested_answer_prompt, suggested_answer) is_valid_gt = validation_res.pass_validation failed_reason = "" if not is_valid_gt: - failed_reason = ErrorMsg.INVALID_ANSWER.format(ground_truth) + failed_reason = ErrorMsg.INVALID_ANSWER.format(suggested_answer) print(failed_reason) - ground_truth = "" + suggested_answer = "" - return {"ground_truth": ground_truth, "validation_res": validation_res} + return {"suggested_answer": suggested_answer, "validation_res": validation_res} diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 similarity index 81% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 index 41cef6ae20b..429bc2313fe 100644 --- a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_ground_truth_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 @@ -5,7 +5,7 @@ The ground truth is not valid if the ground truth suggests that the context does user: Output a json format with the reason and verdict. Here are some examples: -ground_truth: +suggested_answer: The steps to build and install your tool package for use in VS Code extension are not provided in the context. answer: { @@ -13,7 +13,7 @@ answer: "verdict":"no" } -ground_truth: +suggested_answer: The context does not provide specific information on what the possible provider values are in supported configs for a connection provider. answer: { @@ -21,21 +21,21 @@ answer: "verdict":"no" } -ground_truth: +suggested_answer: I don't know. answer: { - "reason":"The ground_truth is invalid because it conveys don't know.", + "reason":"The suggested_answer is invalid because it conveys don't know.", "verdict":"no" } -ground_truth: +suggested_answer: The two essential components of an activate config in a node flow are `activate.when` and `activate.is`. answer: { - "reason":"The ground_truth is valid because it is clear and true.", + "reason":"The suggested_answer is valid because it is clear and true.", "verdict":"yes" } -ground_truth:{{ground_truth}} +suggested_answer:{{suggested_answer}} answer: diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_test_question.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py diff --git a/examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/test_data_gen/construct_test_data_flow/validate_text_trunk_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 diff --git a/examples/test_data_gen/test_data_gen/requirements.txt b/examples/gen_test_data/gen_test_data/requirements.txt similarity index 100% rename from examples/test_data_gen/test_data_gen/requirements.txt rename to examples/gen_test_data/gen_test_data/requirements.txt diff --git a/examples/test_data_gen/test_data_gen/requirements_cloud.txt b/examples/gen_test_data/gen_test_data/requirements_cloud.txt similarity index 100% rename from examples/test_data_gen/test_data_gen/requirements_cloud.txt rename to examples/gen_test_data/gen_test_data/requirements_cloud.txt diff --git a/examples/test_data_gen/test_data_gen/run.py b/examples/gen_test_data/gen_test_data/run.py similarity index 95% rename from examples/test_data_gen/test_data_gen/run.py rename to examples/gen_test_data/gen_test_data/run.py index 2c310cf2388..f8635d30f4a 100644 --- a/examples/test_data_gen/test_data_gen/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -8,9 +8,9 @@ from promptflow import PFClient from promptflow.entities import Run -CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.ini")) +CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) -UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "test_data_gen", "utils")) +UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "gen_test_data", "utils")) if UTILS_PATH not in os.sys.path: os.sys.path.insert(0, UTILS_PATH) @@ -50,9 +50,9 @@ def get_batch_run_output(pf: PFClient, base_run: Run): print(f"#### Start to get batch run {base_run.name} details.") details = pf.get_details(base_run, all_results=True) question = details["outputs.question"].tolist() - ground_truth = details["outputs.ground_truth"].tolist() + suggested_answer = details["outputs.suggested_answer"].tolist() debug_info = details["outputs.debug_info"].tolist() - return [{"question": q, "ground_truth": g, "debug_info": d} for q, g, d in zip(question, ground_truth, debug_info)] + return [{"question": q, "suggested_answer": g, "debug_info": d} for q, g, d in zip(question, suggested_answer, debug_info)] def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): diff --git a/examples/test_data_gen/test_data_gen/utils/__init__.py b/examples/gen_test_data/gen_test_data/utils/__init__.py similarity index 100% rename from examples/test_data_gen/test_data_gen/utils/__init__.py rename to examples/gen_test_data/gen_test_data/utils/__init__.py diff --git a/examples/test_data_gen/test_data_gen/utils/common.py b/examples/gen_test_data/gen_test_data/utils/common.py similarity index 100% rename from examples/test_data_gen/test_data_gen/utils/common.py rename to examples/gen_test_data/gen_test_data/utils/common.py diff --git a/examples/test_data_gen/test_data_gen/utils/components.py b/examples/gen_test_data/gen_test_data/utils/components.py similarity index 100% rename from examples/test_data_gen/test_data_gen/utils/components.py rename to examples/gen_test_data/gen_test_data/utils/components.py diff --git a/examples/test_data_gen/test_data_gen/utils/constants.py b/examples/gen_test_data/gen_test_data/utils/constants.py similarity index 85% rename from examples/test_data_gen/test_data_gen/utils/constants.py rename to examples/gen_test_data/gen_test_data/utils/constants.py index 48a47eb70fe..44ce95c3829 100644 --- a/examples/test_data_gen/test_data_gen/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/utils/constants.py @@ -24,6 +24,6 @@ "validate_and_generate_seed_question": {"connection": "{connection_name}"}, "validate_and_generate_test_question": {"connection": "{connection_name}"}, "validate_test_question": {"connection": "{connection_name}"}, - "generate_ground_truth": {"connection": "{connection_name}"}, - "validate_ground_truth": {"connection": "{connection_name}"} + "generate_suggested_answer": {"connection": "{connection_name}"}, + "validate_suggested_answer": {"connection": "{connection_name}"} } diff --git a/examples/gen_test_data/test_docs/test_doc.docx b/examples/gen_test_data/test_docs/test_doc.docx new file mode 100644 index 0000000000000000000000000000000000000000..60c0a2fbe293c1ae2f62375b519bb54ac2130dda GIT binary patch literal 16235 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 OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "document_node": "{\"id_\": \"839fed91-145c-400c-8076-76041e86b4b5\", \"embedding\": null, \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"70a637e1-53f1-4f40-8023-d658aee58781\", \"node_type\": \"4\", \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"hash\": \"a5b0a2e16236dcbbdf074393d9869fafbf48d53e2eee0dedd5d56c91a3d2b2a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1103188ebae3a0304ea7b359b5fc1ca7c368c3b41477d7797b0367d8dd491cbf\", \"text\": \"Purpose\\n\\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\\n\\n\\n\\nGoal\\n\\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\\n\\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\\n\\nAuthoring/test/evaluation runs\\n\\nBatch inference (prompt flow converted to component running in a pipeline)\\n\\nReal-time inference (prompt flow deployed as online endpoint)\\n\\nHow are the AzureOpenAI APIs called\\n\\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\\n\\n\\n\\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\\n\\n\\n\\nThe call path looks like:\\n\\n\\n\\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\\n\\n\\n\\nWhat custom headers to add\\n\\nx-ms-useragent\\n\\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\\n\\n\\n\\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\\n\\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\\n\\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \\\"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\\\"\\n\\n\\n\\nms-azure-ai-promptflow\\n\\nThis is a customized header for PromptFlow.\\n\\n\\n\\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\\n\\n\\n\\nHeader\\tExplanation\\tValue\\n\\nms-azure-ai-promptflow-run-mode\\tpromptflow run mode\\tFlow, SingleNode, FromNode, BulkTest, Eval\\n\\nms-azure-ai-promptflow-called-from\\tAOAI call source\\taoai-tool - call from built-in aoai tool\\n\\nms-azure-ai-promptflow-subscription-id\\tAML workspace subscription id\\t96aede12-2f73-41cb-b983-6d11a904839b\\n\\nms-azure-ai-promptflow-resource-group\\tAML workspace resource group\\tpromptflow\\n\\nms-azure-ai-promptflow-workspace-name\\tAML workspace name\\tpromptflow-canary-dev\\n\\nms-azure-ai-promptflow-workspace-id\\tAML workspace id\\t\\n\\nms-azure-ai-promptflow-edition\\tpromptflow runtime edition\\tenterprise, community\\n\\nms-azure-ai-promptflow-compute-type\\tpromptflow runtime compute type\\tmanaged_online_deployment, compute_instance, local\\n\\nms-azure-ai-promptflow-runtime-mode\\tpromptflow runtime mode\\tcompute - authoring run, serving - scoring run\\n\\nms-azure-ai-promptflow-flow-id\\trun flow id\\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\\n\\nms-azure-ai-promptflow-root-run-id\\troot run id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73\\n\\nms-azure-ai-promptflow-index\\tindex\\t0\\n\\nms-azure-ai-promptflow-run-id\\trun id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\\n\\nms-azure-ai-promptflow-variant-id\\tvariant id\\tvariant_0\\n\\nReferences\\n\\n\\\"HTTP Headers for Telemetry\\\" from Cognitive Services wiki page \\n\\nThe design doc listed in the wiki page\", \"start_char_idx\": 0, \"end_char_idx\": 3199, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl b/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl new file mode 100644 index 00000000000..0adbc754bc5 --- /dev/null +++ b/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl @@ -0,0 +1 @@ +{"text_chunk": "Purpose\n\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\n\n\n\nGoal\n\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\n\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\n\nAuthoring/test/evaluation runs\n\nBatch inference (prompt flow converted to component running in a pipeline)\n\nReal-time inference (prompt flow deployed as online endpoint)\n\nHow are the AzureOpenAI APIs called\n\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\n\n\n\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\n\n\n\nThe call path looks like:\n\n\n\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "document_node": "{\"id_\": \"1139ef74-304f-42ea-b8f9-3c7986992ff2\", \"embedding\": null, \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bfdc56fa-c8c4-45c8-b1ca-4e6000a1d763\", \"node_type\": \"4\", \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"hash\": \"a5b0a2e16236dcbbdf074393d9869fafbf48d53e2eee0dedd5d56c91a3d2b2a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1103188ebae3a0304ea7b359b5fc1ca7c368c3b41477d7797b0367d8dd491cbf\", \"text\": \"Purpose\\n\\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\\n\\n\\n\\nGoal\\n\\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\\n\\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\\n\\nAuthoring/test/evaluation runs\\n\\nBatch inference (prompt flow converted to component running in a pipeline)\\n\\nReal-time inference (prompt flow deployed as online endpoint)\\n\\nHow are the AzureOpenAI APIs called\\n\\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\\n\\n\\n\\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\\n\\n\\n\\nThe call path looks like:\\n\\n\\n\\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\\n\\n\\n\\nWhat custom headers to add\\n\\nx-ms-useragent\\n\\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\\n\\n\\n\\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\\n\\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\\n\\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \\\"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\\\"\\n\\n\\n\\nms-azure-ai-promptflow\\n\\nThis is a customized header for PromptFlow.\\n\\n\\n\\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\\n\\n\\n\\nHeader\\tExplanation\\tValue\\n\\nms-azure-ai-promptflow-run-mode\\tpromptflow run mode\\tFlow, SingleNode, FromNode, BulkTest, Eval\\n\\nms-azure-ai-promptflow-called-from\\tAOAI call source\\taoai-tool - call from built-in aoai tool\\n\\nms-azure-ai-promptflow-subscription-id\\tAML workspace subscription id\\t96aede12-2f73-41cb-b983-6d11a904839b\\n\\nms-azure-ai-promptflow-resource-group\\tAML workspace resource group\\tpromptflow\\n\\nms-azure-ai-promptflow-workspace-name\\tAML workspace name\\tpromptflow-canary-dev\\n\\nms-azure-ai-promptflow-workspace-id\\tAML workspace id\\t\\n\\nms-azure-ai-promptflow-edition\\tpromptflow runtime edition\\tenterprise, community\\n\\nms-azure-ai-promptflow-compute-type\\tpromptflow runtime compute type\\tmanaged_online_deployment, compute_instance, local\\n\\nms-azure-ai-promptflow-runtime-mode\\tpromptflow runtime mode\\tcompute - authoring run, serving - scoring run\\n\\nms-azure-ai-promptflow-flow-id\\trun flow id\\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\\n\\nms-azure-ai-promptflow-root-run-id\\troot run id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73\\n\\nms-azure-ai-promptflow-index\\tindex\\t0\\n\\nms-azure-ai-promptflow-run-id\\trun id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\\n\\nms-azure-ai-promptflow-variant-id\\tvariant id\\tvariant_0\\n\\nReferences\\n\\n\\\"HTTP Headers for Telemetry\\\" from Cognitive Services wiki page \\n\\nThe design doc listed in the wiki page\", \"start_char_idx\": 0, \"end_char_idx\": 3199, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl b/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl new file mode 100644 index 00000000000..8696226d90e --- /dev/null +++ b/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl @@ -0,0 +1 @@ +{"question": "What is the purpose of custom HTTP headers in AzureOpenAI API calls?", "suggested_answer": "The purpose of custom HTTP headers in AzureOpenAI API calls is for usage tracking by the AzureOpenAI team. These headers facilitate detailed breakdown of usage scenarios such as authoring/test/evaluation runs, batch inference, and real-time inference. They also allow for logging PromptFlow-specific information such as run mode, subscription id, resource group, workspace name, and other metadata related to Azure Machine Learning (AML) workspaces and the PromptFlow usage. Additionally, a custom header like x-ms-useragent is chosen to overcome platform limitations that prevent modifying the default User-Agent header.", "debug_info": {"question_type": "simple", "text_trunk": "Purpose\n\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\n\n\n\nGoal\n\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\n\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\n\nAuthoring/test/evaluation runs\n\nBatch inference (prompt flow converted to component running in a pipeline)\n\nReal-time inference (prompt flow deployed as online endpoint)\n\nHow are the AzureOpenAI APIs called\n\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\n\n\n\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\n\n\n\nThe call path looks like:\n\n\n\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "text_meta": "{}", "generation_summary": {"success": true, "failed_step": "", "failed_reason": ""}, "generation_details": {"text_trunk": {"pass_validation": true, "reason_if_failed": null}, "seed_question": {"generated_question": "What is the purpose of custom HTTP headers in AzureOpenAI API calls?", "pass_validation": true, "reason_if_failed": null}, "suggested_answer": {"generated_suggested_answer": "The purpose of custom HTTP headers in AzureOpenAI API calls is for usage tracking by the AzureOpenAI team. These headers facilitate detailed breakdown of usage scenarios such as authoring/test/evaluation runs, batch inference, and real-time inference. They also allow for logging PromptFlow-specific information such as run mode, subscription id, resource group, workspace name, and other metadata related to Azure Machine Learning (AML) workspaces and the PromptFlow usage. Additionally, a custom header like x-ms-useragent is chosen to overcome platform limitations that prevent modifying the default User-Agent header.", "pass_validation": true, "reason_if_failed": null}}}} From cc6e2a433f1a3003b08754f0649a8db60e1aef4a Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 15:22:41 +0800 Subject: [PATCH 029/112] remove docs --- examples/gen_test_data/test_docs/test_doc.docx | Bin 16235 -> 0 bytes .../Jan-30-2024-15-16-20/document_nodes.jsonl | 1 - .../Jan-30-2024-15-17-41/document_nodes.jsonl | 1 - .../output/Jan-30-2024-15-17-41/test-data.jsonl | 1 - 4 files changed, 3 deletions(-) delete mode 100644 examples/gen_test_data/test_docs/test_doc.docx delete mode 100644 examples/test_data_gen/output/Jan-30-2024-15-16-20/document_nodes.jsonl delete mode 100644 examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl delete mode 100644 examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl diff --git a/examples/gen_test_data/test_docs/test_doc.docx b/examples/gen_test_data/test_docs/test_doc.docx deleted file mode 100644 index 60c0a2fbe293c1ae2f62375b519bb54ac2130dda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16235 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 OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "document_node": "{\"id_\": \"839fed91-145c-400c-8076-76041e86b4b5\", \"embedding\": null, \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"70a637e1-53f1-4f40-8023-d658aee58781\", \"node_type\": \"4\", \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"hash\": \"a5b0a2e16236dcbbdf074393d9869fafbf48d53e2eee0dedd5d56c91a3d2b2a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1103188ebae3a0304ea7b359b5fc1ca7c368c3b41477d7797b0367d8dd491cbf\", \"text\": \"Purpose\\n\\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\\n\\n\\n\\nGoal\\n\\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\\n\\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\\n\\nAuthoring/test/evaluation runs\\n\\nBatch inference (prompt flow converted to component running in a pipeline)\\n\\nReal-time inference (prompt flow deployed as online endpoint)\\n\\nHow are the AzureOpenAI APIs called\\n\\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\\n\\n\\n\\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\\n\\n\\n\\nThe call path looks like:\\n\\n\\n\\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\\n\\n\\n\\nWhat custom headers to add\\n\\nx-ms-useragent\\n\\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\\n\\n\\n\\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\\n\\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\\n\\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \\\"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\\\"\\n\\n\\n\\nms-azure-ai-promptflow\\n\\nThis is a customized header for PromptFlow.\\n\\n\\n\\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\\n\\n\\n\\nHeader\\tExplanation\\tValue\\n\\nms-azure-ai-promptflow-run-mode\\tpromptflow run mode\\tFlow, SingleNode, FromNode, BulkTest, Eval\\n\\nms-azure-ai-promptflow-called-from\\tAOAI call source\\taoai-tool - call from built-in aoai tool\\n\\nms-azure-ai-promptflow-subscription-id\\tAML workspace subscription id\\t96aede12-2f73-41cb-b983-6d11a904839b\\n\\nms-azure-ai-promptflow-resource-group\\tAML workspace resource group\\tpromptflow\\n\\nms-azure-ai-promptflow-workspace-name\\tAML workspace name\\tpromptflow-canary-dev\\n\\nms-azure-ai-promptflow-workspace-id\\tAML workspace id\\t\\n\\nms-azure-ai-promptflow-edition\\tpromptflow runtime edition\\tenterprise, community\\n\\nms-azure-ai-promptflow-compute-type\\tpromptflow runtime compute type\\tmanaged_online_deployment, compute_instance, local\\n\\nms-azure-ai-promptflow-runtime-mode\\tpromptflow runtime mode\\tcompute - authoring run, serving - scoring run\\n\\nms-azure-ai-promptflow-flow-id\\trun flow id\\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\\n\\nms-azure-ai-promptflow-root-run-id\\troot run id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73\\n\\nms-azure-ai-promptflow-index\\tindex\\t0\\n\\nms-azure-ai-promptflow-run-id\\trun id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\\n\\nms-azure-ai-promptflow-variant-id\\tvariant id\\tvariant_0\\n\\nReferences\\n\\n\\\"HTTP Headers for Telemetry\\\" from Cognitive Services wiki page \\n\\nThe design doc listed in the wiki page\", \"start_char_idx\": 0, \"end_char_idx\": 3199, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl b/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl deleted file mode 100644 index 0adbc754bc5..00000000000 --- a/examples/test_data_gen/output/Jan-30-2024-15-17-41/document_nodes.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"text_chunk": "Purpose\n\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\n\n\n\nGoal\n\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\n\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\n\nAuthoring/test/evaluation runs\n\nBatch inference (prompt flow converted to component running in a pipeline)\n\nReal-time inference (prompt flow deployed as online endpoint)\n\nHow are the AzureOpenAI APIs called\n\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\n\n\n\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\n\n\n\nThe call path looks like:\n\n\n\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "document_node": "{\"id_\": \"1139ef74-304f-42ea-b8f9-3c7986992ff2\", \"embedding\": null, \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bfdc56fa-c8c4-45c8-b1ca-4e6000a1d763\", \"node_type\": \"4\", \"metadata\": {\"file_name\": \"test_doc.docx\", \"file_path\": \"C:\\\\Users\\\\chesi\\\\dcmcode\\\\github-microsoft-promptflow\\\\promptflow\\\\examples\\\\gen_test_data\\\\test_docs\\\\test_doc.docx\", \"file_type\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", \"file_size\": 16235, \"creation_date\": \"2024-01-24\", \"last_modified_date\": \"2024-01-24\", \"last_accessed_date\": \"2024-01-30\"}, \"hash\": \"a5b0a2e16236dcbbdf074393d9869fafbf48d53e2eee0dedd5d56c91a3d2b2a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1103188ebae3a0304ea7b359b5fc1ca7c368c3b41477d7797b0367d8dd491cbf\", \"text\": \"Purpose\\n\\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\\n\\n\\n\\nGoal\\n\\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\\n\\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\\n\\nAuthoring/test/evaluation runs\\n\\nBatch inference (prompt flow converted to component running in a pipeline)\\n\\nReal-time inference (prompt flow deployed as online endpoint)\\n\\nHow are the AzureOpenAI APIs called\\n\\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\\n\\n\\n\\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\\n\\n\\n\\nThe call path looks like:\\n\\n\\n\\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\\n\\n\\n\\nWhat custom headers to add\\n\\nx-ms-useragent\\n\\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\\n\\n\\n\\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\\n\\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\\n\\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \\\"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\\\"\\n\\n\\n\\nms-azure-ai-promptflow\\n\\nThis is a customized header for PromptFlow.\\n\\n\\n\\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\\n\\n\\n\\nHeader\\tExplanation\\tValue\\n\\nms-azure-ai-promptflow-run-mode\\tpromptflow run mode\\tFlow, SingleNode, FromNode, BulkTest, Eval\\n\\nms-azure-ai-promptflow-called-from\\tAOAI call source\\taoai-tool - call from built-in aoai tool\\n\\nms-azure-ai-promptflow-subscription-id\\tAML workspace subscription id\\t96aede12-2f73-41cb-b983-6d11a904839b\\n\\nms-azure-ai-promptflow-resource-group\\tAML workspace resource group\\tpromptflow\\n\\nms-azure-ai-promptflow-workspace-name\\tAML workspace name\\tpromptflow-canary-dev\\n\\nms-azure-ai-promptflow-workspace-id\\tAML workspace id\\t\\n\\nms-azure-ai-promptflow-edition\\tpromptflow runtime edition\\tenterprise, community\\n\\nms-azure-ai-promptflow-compute-type\\tpromptflow runtime compute type\\tmanaged_online_deployment, compute_instance, local\\n\\nms-azure-ai-promptflow-runtime-mode\\tpromptflow runtime mode\\tcompute - authoring run, serving - scoring run\\n\\nms-azure-ai-promptflow-flow-id\\trun flow id\\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\\n\\nms-azure-ai-promptflow-root-run-id\\troot run id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73\\n\\nms-azure-ai-promptflow-index\\tindex\\t0\\n\\nms-azure-ai-promptflow-run-id\\trun id\\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\\n\\nms-azure-ai-promptflow-variant-id\\tvariant id\\tvariant_0\\n\\nReferences\\n\\n\\\"HTTP Headers for Telemetry\\\" from Cognitive Services wiki page \\n\\nThe design doc listed in the wiki page\", \"start_char_idx\": 0, \"end_char_idx\": 3199, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl b/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl deleted file mode 100644 index 8696226d90e..00000000000 --- a/examples/test_data_gen/output/Jan-30-2024-15-17-41/test-data.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"question": "What is the purpose of custom HTTP headers in AzureOpenAI API calls?", "suggested_answer": "The purpose of custom HTTP headers in AzureOpenAI API calls is for usage tracking by the AzureOpenAI team. These headers facilitate detailed breakdown of usage scenarios such as authoring/test/evaluation runs, batch inference, and real-time inference. They also allow for logging PromptFlow-specific information such as run mode, subscription id, resource group, workspace name, and other metadata related to Azure Machine Learning (AML) workspaces and the PromptFlow usage. Additionally, a custom header like x-ms-useragent is chosen to overcome platform limitations that prevent modifying the default User-Agent header.", "debug_info": {"question_type": "simple", "text_trunk": "Purpose\n\nWe need to be able to set proper HTTP headers when calling AzureOpenAI APIs to make it possible for AzureOpenAI team for usage tracking.\n\n\n\nGoal\n\nFollow the guidelines from AzureOpenAI team on HTTP header definitions.\n\nShould be able to break down detailed PromptFlow usage scenarios, i.e.:\n\nAuthoring/test/evaluation runs\n\nBatch inference (prompt flow converted to component running in a pipeline)\n\nReal-time inference (prompt flow deployed as online endpoint)\n\nHow are the AzureOpenAI APIs called\n\nThe Azure OpenAI APIs are called by the OpenAI Python SDK. See here for details.\n\n\n\nOpenAI Python SDK will set some default headers when calling Azure OpenAI APIs. In addition, it also allows the callers (PromptFlow sdk for this case) define some custom HTTP headers.\n\n\n\nThe call path looks like:\n\n\n\nPromptFlow SDK --(call with custom headers)--> OpenAI Python SDK --(call with custom headers + OpenAI populated headers)--> Azure OpenAI API\n\n\n\nWhat custom headers to add\n\nx-ms-useragent\n\nThe value should look like promptflow-runtime/{version} promptflow-sdk/{version}.\n\n\n\nThe promptflow-sdk part is a fixed value, which indicates that the request was from PromptFlow.\n\nThe {version} part is PromptFlow defined value. It might be either a semver like 0.0.1 or a git commit hash. This field is for PromptFlow internal usage only and the format might change in the future.\n\nAs mentioned above, we call Azure OpenAI's endpoint via the OpenAI's python library, which is not owned by our team. We chose x-ms-useragent rather than the default User-Agent due to \"This header is used when the platform does not support changing the User-Agent (i.e. in a browser).\"\n\n\n\nms-azure-ai-promptflow\n\nThis is a customized header for PromptFlow.\n\n\n\nAccording to the design doc , all the headers that start from ms-azure-ai- will be logged. We chose this field to log some PromptFlow-specific information.\n\n\n\nHeader\tExplanation\tValue\n\nms-azure-ai-promptflow-run-mode\tpromptflow run mode\tFlow, SingleNode, FromNode, BulkTest, Eval\n\nms-azure-ai-promptflow-called-from\tAOAI call source\taoai-tool - call from built-in aoai tool\n\nms-azure-ai-promptflow-subscription-id\tAML workspace subscription id\t96aede12-2f73-41cb-b983-6d11a904839b\n\nms-azure-ai-promptflow-resource-group\tAML workspace resource group\tpromptflow\n\nms-azure-ai-promptflow-workspace-name\tAML workspace name\tpromptflow-canary-dev\n\nms-azure-ai-promptflow-workspace-id\tAML workspace id\t\n\nms-azure-ai-promptflow-edition\tpromptflow runtime edition\tenterprise, community\n\nms-azure-ai-promptflow-compute-type\tpromptflow runtime compute type\tmanaged_online_deployment, compute_instance, local\n\nms-azure-ai-promptflow-runtime-mode\tpromptflow runtime mode\tcompute - authoring run, serving - scoring run\n\nms-azure-ai-promptflow-flow-id\trun flow id\tb6736c3d-5446-4b21-9fd1-c7f1246e67c3\n\nms-azure-ai-promptflow-root-run-id\troot run id\t63ea2263-90ab-4473-b9dc-0e47a55eef73\n\nms-azure-ai-promptflow-index\tindex\t0\n\nms-azure-ai-promptflow-run-id\trun id\t63ea2263-90ab-4473-b9dc-0e47a55eef73_0\n\nms-azure-ai-promptflow-variant-id\tvariant id\tvariant_0\n\nReferences\n\n\"HTTP Headers for Telemetry\" from Cognitive Services wiki page \n\nThe design doc listed in the wiki page", "text_meta": "{}", "generation_summary": {"success": true, "failed_step": "", "failed_reason": ""}, "generation_details": {"text_trunk": {"pass_validation": true, "reason_if_failed": null}, "seed_question": {"generated_question": "What is the purpose of custom HTTP headers in AzureOpenAI API calls?", "pass_validation": true, "reason_if_failed": null}, "suggested_answer": {"generated_suggested_answer": "The purpose of custom HTTP headers in AzureOpenAI API calls is for usage tracking by the AzureOpenAI team. These headers facilitate detailed breakdown of usage scenarios such as authoring/test/evaluation runs, batch inference, and real-time inference. They also allow for logging PromptFlow-specific information such as run mode, subscription id, resource group, workspace name, and other metadata related to Azure Machine Learning (AML) workspaces and the PromptFlow usage. Additionally, a custom header like x-ms-useragent is chosen to overcome platform limitations that prevent modifying the default User-Agent header.", "pass_validation": true, "reason_if_failed": null}}}} From 9594414ce6884b2d37d1460ff810d79013de63a0 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 15:24:07 +0800 Subject: [PATCH 030/112] remove config.ini --- .../gen_test_data/gen_test_data/config.ini | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 examples/gen_test_data/gen_test_data/config.ini diff --git a/examples/gen_test_data/gen_test_data/config.ini b/examples/gen_test_data/gen_test_data/config.ini deleted file mode 100644 index 90b16322e03..00000000000 --- a/examples/gen_test_data/gen_test_data/config.ini +++ /dev/null @@ -1,34 +0,0 @@ -; config.ini -; This is a sample configuration file - -[COMMON] -; The COMMON section provides common values for all other sections. -; Configure both 'documents_folder' and 'document_chunk_size' if you require document splitting. -; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. -; When all these parameters are configured, the system will primarily use the 'document_nodes_file' -documents_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\gen_test_data\test_docs" -document_chunk_size = 1024 -document_nodes_file = "" - -; Test data gen flow configs -flow_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\gen_test_data\gen_test_data\generate_test_data_flow" ; There is must one flow.dag.yaml file under this folder as entry -connection_name = "open-ai-connection" - - -[LOCAL] -; This section is for local test data generation related configuration. -output_folder = "C:\Users\chesi\dcmcode\github-microsoft-promptflow\promptflow\examples\test_data_gen\output" -flow_batch_run_size = 10 - - -[PIPELINE] -; This section is for cloud test data generation related configuration. -subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" -resource_group = "promptflow" -workspace_name = "yaopfeus" -aml_cluster = "cpu-cluster" - -; Parallel run step configs -prs_instance_count = 2 -prs_mini_batch_size = "10kb" -prs_max_concurrency_per_instance = 10 From afd703cbc213f8f05384966591df265ce0ec205c Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 15:43:04 +0800 Subject: [PATCH 031/112] fix flake 8 --- .../generate_debug_info.py | 15 ++++++++------- .../generate_test_data_flow/utils.py | 1 - .../validate_suggested_answer.py | 3 ++- examples/gen_test_data/gen_test_data/run.py | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index 647af7bbc3b..d396d506126 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -8,12 +8,12 @@ # Please update the function name/signature per need @tool def my_python_tool( - question_type: str, - text_trunk: str, - text_meta: dict = None, - validate_and_generate_seed_question_output: dict = None, - validate_and_generate_test_question_output: dict = None, - validate_suggested_answer_output: ValidationResult = None, + question_type: str, + text_trunk: str, + text_meta: dict = None, + validate_and_generate_seed_question_output: dict = None, + validate_and_generate_test_question_output: dict = None, + validate_suggested_answer_output: ValidationResult = None, ) -> dict: text_trunk_validation_res = validate_and_generate_seed_question_output["validation_res"] generated_seed_question = validate_and_generate_seed_question_output["question"] @@ -24,7 +24,8 @@ def my_python_tool( is_generation_success = generated_suggested_answer != "" is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None is_seed_question_valid = seed_question_validation_res.pass_validation if seed_question_validation_res else None - is_suggested_answer_valid = suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None + is_suggested_answer_valid = suggested_answer_validation_res.pass_validation \ + if suggested_answer_validation_res else None failed_step = "" failed_reason = "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index 4766849bff7..adcba803ec4 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -1,7 +1,6 @@ import json import re from collections import namedtuple -from enum import Enum import numpy as np import numpy.testing as npt diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 008c0705457..6cb7a282097 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -25,7 +25,8 @@ def validate_suggested_answer( if not suggested_answer: return {"suggested_answer": "", "validation_res": None} - validation_res = get_suggested_answer_validation_res(connection, model, validate_suggested_answer_prompt, suggested_answer) + validation_res = get_suggested_answer_validation_res(connection, model, + validate_suggested_answer_prompt, suggested_answer) is_valid_gt = validation_res.pass_validation failed_reason = "" if not is_valid_gt: diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index f8635d30f4a..01e67cff47a 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -52,7 +52,8 @@ def get_batch_run_output(pf: PFClient, base_run: Run): question = details["outputs.question"].tolist() suggested_answer = details["outputs.suggested_answer"].tolist() debug_info = details["outputs.debug_info"].tolist() - return [{"question": q, "suggested_answer": g, "debug_info": d} for q, g, d in zip(question, suggested_answer, debug_info)] + return [{"question": q, "suggested_answer": g, "debug_info": d} + for q, g, d in zip(question, suggested_answer, debug_info)] def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): From 7c0ee33aa8eaa72dc2cc7461341fc78ee9d762f5 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 16:55:39 +0800 Subject: [PATCH 032/112] add logger --- examples/gen_test_data/gen_test_data/run.py | 18 ++++++++++-------- .../gen_test_data/utils/common.py | 16 +++++++++------- .../gen_test_data/utils/constants.py | 3 ++- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 01e67cff47a..604f9866724 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -6,6 +6,7 @@ from azure.identity import DefaultAzureCredential from promptflow import PFClient +from promptflow._utils.logger_utils import get_logger from promptflow.entities import Run CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) @@ -18,6 +19,8 @@ from common import split_document, clean_data_and_save # noqa: E402 from components import clean_test_data_set, document_split # noqa: E402 +logger = get_logger("data.gen") + def batch_run_flow( pf: PFClient, @@ -26,7 +29,7 @@ def batch_run_flow( flow_batch_run_size: int, connection_name: str = "azure_open_ai_connection", ): - print("#### Start to submit the batch run.") + logger.info("Start to submit the batch run.") base_run = pf.run( flow=flow_folder, data=flow_input_data, @@ -40,14 +43,13 @@ def batch_run_flow( column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, ) - - print("#### Batch run is completed.") + logger.info("Batch run is completed.") return base_run def get_batch_run_output(pf: PFClient, base_run: Run): - print(f"#### Start to get batch run {base_run.name} details.") + logger.info(f"Start to get batch run {base_run.name} details.") details = pf.get_details(base_run, all_results=True) question = details["outputs.question"].tolist() suggested_answer = details["outputs.suggested_answer"].tolist() @@ -75,7 +77,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str "max_concurrency_per_instance", ] ) -def test_data_gen_pipeline_with_flow( +def gen_test_data_pipeline( data_input: Input, flow_yml_path: str, connection_name: str, @@ -161,7 +163,7 @@ def run_cloud( "max_concurrency_per_instance": prs_max_concurrency_per_instance, } - pipeline_with_flow = test_data_gen_pipeline_with_flow( + pipeline_with_flow = gen_test_data_pipeline( data_input=data_input, flow_yml_path=os.path.join(flow_folder, "flow.dag.yaml"), connection_name=connection_name, @@ -170,8 +172,8 @@ def run_cloud( **prs_configs, ) pipeline_with_flow.compute = aml_cluster - print("Completed to submit pipeline. Experiment Link: ", - ml_client.jobs.create_or_update(pipeline_with_flow).studio_url) + studio_url = ml_client.jobs.create_or_update(pipeline_with_flow).studio_url + logger.info(f"Completed to submit pipeline. Experiment Link: {studio_url}") if __name__ == "__main__": diff --git a/examples/gen_test_data/gen_test_data/utils/common.py b/examples/gen_test_data/gen_test_data/utils/common.py index 973cd53ff8d..60e3f12e734 100644 --- a/examples/gen_test_data/gen_test_data/utils/common.py +++ b/examples/gen_test_data/gen_test_data/utils/common.py @@ -4,6 +4,7 @@ from pathlib import Path from constants import DOCUMENT_NODE, TEXT_CHUNK +from promptflow._utils.logger_utils import get_logger try: from llama_index import SimpleDirectoryReader @@ -17,12 +18,12 @@ def split_document(chunk_size, documents_folder, document_node_output): - # load docs - print("#### Start to split the documents.") + logger = get_logger("doc.split") + logger.info("Start to split the documents.") documents = SimpleDirectoryReader( documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" ).load_data() - print(f"#### Collect {len(documents)} documents.") + logger.info(f"Collect {len(documents)} documents.") # Convert documents into nodes node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) @@ -32,13 +33,14 @@ def split_document(chunk_size, documents_folder, document_node_output): for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) - print(f"#### End to split the documents and generate {len(document_nodes)} document nodes.") + logger.info(f"End to split the documents and generate {len(document_nodes)} document nodes.") return str((Path(document_node_output) / "document_nodes.jsonl")) def clean_data_and_save(test_data_set: list, test_data_output_path: str): - print("#### Start to clean the data.") + logger = get_logger("data.clean") + logger.info("Start to clean the data.") cleaned_data = [] for test_data in test_data_set: @@ -52,6 +54,6 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): print(f"{jsonl_str}", file=text_file) test_data_count = len(cleaned_data) - print( - f"#### Completed to clean {len(test_data_set) - test_data_count} invalid test data " + logger.info( + f"Completed to clean {len(test_data_set) - test_data_count} invalid test data " f"and collect {test_data_count} test data to {test_data_output_path}.") diff --git a/examples/gen_test_data/gen_test_data/utils/constants.py b/examples/gen_test_data/gen_test_data/utils/constants.py index 44ce95c3829..bc9d55e6eb0 100644 --- a/examples/gen_test_data/gen_test_data/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/utils/constants.py @@ -13,7 +13,8 @@ "pip": [ "mldesigner==0.1.0b17", "llama_index", - "docx2txt" + "docx2txt", + "promptflow" ] }, ], From cf03e5f81cf0fe49b10863adcba132e199af07c9 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 17:26:00 +0800 Subject: [PATCH 033/112] refine logs --- examples/gen_test_data/gen_test_data/utils/common.py | 8 ++++---- examples/gen_test_data/gen_test_data/utils/components.py | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/utils/common.py b/examples/gen_test_data/gen_test_data/utils/common.py index 60e3f12e734..00b9552c79f 100644 --- a/examples/gen_test_data/gen_test_data/utils/common.py +++ b/examples/gen_test_data/gen_test_data/utils/common.py @@ -40,7 +40,8 @@ def split_document(chunk_size, documents_folder, document_node_output): def clean_data_and_save(test_data_set: list, test_data_output_path: str): logger = get_logger("data.clean") - logger.info("Start to clean the data.") + logger.info(f"Collected {len(test_data_set)} test data after the batch run. " + f"Initiating data cleaning process.") cleaned_data = [] for test_data in test_data_set: @@ -53,7 +54,6 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): with open(test_data_output_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - test_data_count = len(cleaned_data) logger.info( - f"Completed to clean {len(test_data_set) - test_data_count} invalid test data " - f"and collect {test_data_count} test data to {test_data_output_path}.") + f"Collected {len(cleaned_data)} valid test data. " + f"The cleaned data has been saved to {test_data_output_path}.") diff --git a/examples/gen_test_data/gen_test_data/utils/components.py b/examples/gen_test_data/gen_test_data/utils/components.py index 914573bccb5..515cdc947fc 100644 --- a/examples/gen_test_data/gen_test_data/utils/components.py +++ b/examples/gen_test_data/gen_test_data/utils/components.py @@ -27,7 +27,6 @@ def document_split( Returns: The folder containing the split documents. """ - print("files in input path: ", os.listdir(documents_folder)) return split_document(chunk_size, documents_folder, document_node_output) @@ -42,9 +41,7 @@ def clean_test_data_set( test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") ) -> str: test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" - print("test_data_file path: %s" % test_data_set_path) - print("reading file: %s ..." % test_data_set_path) with open(test_data_set_path, "r") as f: data = [json.loads(line) for line in f] From 838f535acfddf59f143aa00efb01e7fc45e16f77 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 18:22:42 +0800 Subject: [PATCH 034/112] rename flow some parameters --- ...uct-test-data.md => generate-test-data.md} | 0 .../generate_test_data_flow/flow.dag.yaml | 23 ++++++++-- .../generate_suggested_answer.py | 11 ++++- .../generate_test_data_flow/utils.py | 46 ++++++++++++++----- .../validate_and_generate_seed_question.py | 13 ++++-- .../validate_and_generate_test_question.py | 8 ++-- .../validate_suggested_answer.py | 8 ++-- .../validate_test_question.py | 6 ++- .../gen_test_data/utils/components.py | 4 +- 9 files changed, 87 insertions(+), 32 deletions(-) rename docs/how-to-guides/{construct-test-data.md => generate-test-data.md} (100%) diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/generate-test-data.md similarity index 100% rename from docs/how-to-guides/construct-test-data.md rename to docs/how-to-guides/generate-test-data.md diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index b2c589839b8..9b7ca715219 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -5,6 +5,9 @@ inputs: text_chunk: type: string is_chat_input: false + default: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born + theoretical physicist who is widely held to be one of the greatest and + most influential scientists of all time. text_meta: type: string default: "{}" @@ -59,10 +62,12 @@ nodes: path: validate_and_generate_seed_question.py inputs: connection: open-ai-connection - model: gpt-4 + model_or_deployment_name: gpt-4 validate_text_trunk_prompt: ${validate_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} context: ${inputs.text_chunk} + temperature: 1 + max_tokens: 512 use_variants: false - name: validate_and_generate_test_question type: python @@ -71,10 +76,12 @@ nodes: path: validate_and_generate_test_question.py inputs: connection: open-ai-connection - model: gpt-4 + model_or_deployment_name: gpt-4 validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output.question} response_format: "" + temperature: 1 + max_tokens: 512 use_variants: false - name: validate_question_prompt type: prompt @@ -91,9 +98,11 @@ nodes: path: validate_test_question.py inputs: connection: open-ai-connection - model: gpt-4 + model_or_deployment_name: gpt-4 question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} + temperature: 1 + max_tokens: 512 use_variants: false - name: generate_suggested_answer type: python @@ -104,8 +113,10 @@ nodes: connection: open-ai-connection context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} - model: gpt-4 question: ${validate_test_question.output} + model_or_deployment_name: gpt-4 + temperature: 1 + max_tokens: 512 use_variants: false - name: generate_debug_info type: python @@ -133,6 +144,8 @@ nodes: path: validate_suggested_answer.py inputs: connection: open-ai-connection - model: gpt-4 + model_or_deployment_name: gpt-4 suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} + temperature: 1 + max_tokens: 512 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index e83cd7d0124..a16f99d060b 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -9,10 +9,12 @@ @tool def generate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, + model_or_deployment_name: str, question: str, context: str, generate_suggested_answer_prompt: str, + temperature: float = 1.0, + max_tokens: int = 512 ): """ Generates a ground truth based on the given prompts and context information. @@ -21,6 +23,11 @@ def generate_suggested_answer( str: The generated ground truth. """ if question and context: - return llm_call(connection, model, generate_suggested_answer_prompt) + return llm_call( + connection, + model_or_deployment_name, + generate_suggested_answer_prompt, + temperature=temperature, + max_tokens=max_tokens) else: return "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index adcba803ec4..f3c335c2864 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -39,15 +39,33 @@ class ErrorMsg: ValidationResult = namedtuple("ValidationResult", ["pass_validation", "reason_if_failed"]) -def llm_call(connection, model, prompt, response_format=ResponseFormat.TEXT): +def llm_call( + connection, + model_or_deployment_name, + prompt, + response_format=ResponseFormat.TEXT, + temperature=1.0, + max_tokens=16 +): response_format = "json_object" if response_format.lower() == "json" else response_format prompt = f"{{% raw %}}{prompt}{{% endraw %}}" if isinstance(connection, AzureOpenAIConnection): return aoai_chat( - connection=connection, prompt=prompt, deployment_name=model, response_format={"type": response_format} + connection=connection, + prompt=prompt, + deployment_name=model_or_deployment_name, + temperature=temperature, + max_tokens=max_tokens, + response_format={"type": response_format} ) elif isinstance(connection, OpenAIConnection): - return openai_chat(connection=connection, prompt=prompt, model=model, response_format={"type": response_format}) + return openai_chat( + connection=connection, + prompt=prompt, + model=model_or_deployment_name, + temperature=temperature, + max_tokens=max_tokens, + response_format={"type": response_format}) def get_question_type(testset_distribution) -> str: @@ -59,20 +77,23 @@ def get_question_type(testset_distribution) -> str: return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) -def get_suggested_answer_validation_res(connection, model, prompt, suggested_answer: str): - rsp = llm_call(connection, model, prompt) +def get_suggested_answer_validation_res(connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, + max_tokens: int): + rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens) return retrieve_verdict_and_print_reason( rsp=rsp, validate_obj_name=ValidateObj.SUGGESTED_ANSWER, validate_obj=suggested_answer ) -def get_question_validation_res(connection, model, prompt, question: str, response_format: ResponseFormat): - rsp = llm_call(connection, model, prompt, response_format) +def get_question_validation_res(connection, model_or_deployment_name, prompt, question: str, response_format: ResponseFormat, temperature: float, + max_tokens: int): + rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) -def get_text_trunk_validation_res(connection, model, prompt, context: str, response_format: ResponseFormat): - rsp = llm_call(connection, model, prompt, response_format) +def get_text_trunk_validation_res(connection, model_or_deployment_name, prompt, context: str, response_format: ResponseFormat, temperature: float, + max_tokens: int): + rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context) @@ -112,13 +133,14 @@ def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): def generate_question( - connection, model, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None + connection, model_or_deployment_name, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None, temperature: float = None, + max_tokens: int = None ): if question_type == QuestionType.SIMPLE: return seed_question elif question_type == QuestionType.REASONING: - return llm_call(connection, model, reasoning_prompt) + return llm_call(connection, model_or_deployment_name, reasoning_prompt, temperature=temperature, max_tokens=max_tokens) elif question_type == QuestionType.CONDITIONAL: - return llm_call(connection, model, conditional_prompt) + return llm_call(connection, model_or_deployment_name, conditional_prompt, temperature=temperature, max_tokens=max_tokens) else: raise Exception("Invalid question type.") diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py index 0b8a01be866..2f343e196e4 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py @@ -9,11 +9,13 @@ @tool def validate_and_generate_seed_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, + model_or_deployment_name: str, validate_text_trunk_prompt: str, seed_question_prompt: str, context: str = None, response_format: str = ResponseFormat.JSON, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given text chunk. @@ -23,7 +25,7 @@ def validate_and_generate_seed_question( dict: The generated seed question and text trunk validation result. """ validation_res = get_text_trunk_validation_res( - connection, model, validate_text_trunk_prompt, context, response_format + connection, model_or_deployment_name, validate_text_trunk_prompt, context, response_format, temperature, max_tokens ) is_valid_text_trunk = validation_res.pass_validation if not is_valid_text_trunk: @@ -31,5 +33,10 @@ def validate_and_generate_seed_question( print(f"yaodebug: {validation_res}") return {"question": "", "validation_res": validation_res} - seed_question = llm_call(connection, model, seed_question_prompt) + seed_question = llm_call( + connection, + model_or_deployment_name, + seed_question_prompt, + temperature=temperature, + max_tokens=max_tokens) return {"question": seed_question, "validation_res": validation_res} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py index 8cc128ed1f0..f96dc7c7640 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py @@ -9,7 +9,7 @@ @tool def validate_and_generate_test_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, + model_or_deployment_name: str, seed_question: str, # reasoning_prompt: str, # conditional_prompt: str, @@ -18,6 +18,8 @@ def validate_and_generate_test_question( # reasoning_ratio: float = 0.25, # conditional_ratio: float = 0.25, response_format: str = ResponseFormat.JSON, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given seed question. @@ -31,7 +33,7 @@ def validate_and_generate_test_question( return {"question": "", "question_type": "", "validation_res": None} validation_res = get_question_validation_res( - connection, model, validate_seed_question_prompt, seed_question, response_format + connection, model_or_deployment_name, validate_seed_question_prompt, seed_question, response_format, temperature, max_tokens ) is_valid_seed_question = validation_res.pass_validation question = "" @@ -46,7 +48,7 @@ def validate_and_generate_test_question( # testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) # question_type = get_question_type(testset_distribution) - # question = generate_question(connection, model, question_type, seed_question) + # question = generate_question(connection, model_or_deployment_name, question_type, seed_question) question = seed_question question_type = QuestionType.SIMPLE diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 6cb7a282097..a7ab9285626 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -12,9 +12,11 @@ @tool def validate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, + model_or_deployment_name: str, suggested_answer: str, validate_suggested_answer_prompt: str, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given ground truth. @@ -25,8 +27,8 @@ def validate_suggested_answer( if not suggested_answer: return {"suggested_answer": "", "validation_res": None} - validation_res = get_suggested_answer_validation_res(connection, model, - validate_suggested_answer_prompt, suggested_answer) + validation_res = get_suggested_answer_validation_res(connection, model_or_deployment_name, + validate_suggested_answer_prompt, suggested_answer, temperature, max_tokens) is_valid_gt = validation_res.pass_validation failed_reason = "" if not is_valid_gt: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py index 7b085adb8d7..1c1b7689c6e 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py @@ -9,10 +9,12 @@ @tool def validate_test_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, + model_or_deployment_name: str, question_info: dict, # generate_context_prompt: str, validate_question_prompt: str, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given question. @@ -29,7 +31,7 @@ def validate_test_question( if question_type == QuestionType.SIMPLE: return question - validation_res = get_question_validation_res(connection, model, validate_question_prompt, question) + validation_res = get_question_validation_res(connection, model_or_deployment_name, validate_question_prompt, question, temperature, max_tokens) is_valid_test_question = validation_res.pass_validation if not is_valid_test_question: print(f"Invalid test question: {question}") diff --git a/examples/gen_test_data/gen_test_data/utils/components.py b/examples/gen_test_data/gen_test_data/utils/components.py index 515cdc947fc..253173655ab 100644 --- a/examples/gen_test_data/gen_test_data/utils/components.py +++ b/examples/gen_test_data/gen_test_data/utils/components.py @@ -10,7 +10,7 @@ @command_component( name="document_split", version="1.0.4", - display_name="Split documents", + display_name="split documents", description="Split documents into chunks.", environment=ENVIRONMENT_DICT_FIXED_VERSION, ) @@ -33,7 +33,7 @@ def document_split( @command_component( name="clean_test_data_set", version="1.0.4", - display_name="Clean dataset", + display_name="clean dataset", description="Clean test data set to remove empty lines.", environment=ENVIRONMENT_DICT_FIXED_VERSION, ) From b27c99a40238f7be87184c6cc30fb5103c7abf07 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 18:26:02 +0800 Subject: [PATCH 035/112] fix flake 8 --- .../generate_test_data_flow/utils.py | 42 +++++++++++-------- .../validate_and_generate_seed_question.py | 24 +++++++---- .../validate_suggested_answer.py | 15 +++---- .../validate_test_question.py | 17 ++++---- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index f3c335c2864..e7c9fe87532 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -5,11 +5,11 @@ import numpy as np import numpy.testing as npt from numpy.random import default_rng - -from promptflow.connections import AzureOpenAIConnection, OpenAIConnection from promptflow.tools.aoai import chat as aoai_chat from promptflow.tools.openai import chat as openai_chat +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + class QuestionType: SIMPLE = "simple" @@ -40,12 +40,12 @@ class ErrorMsg: def llm_call( - connection, - model_or_deployment_name, - prompt, - response_format=ResponseFormat.TEXT, - temperature=1.0, - max_tokens=16 + connection, + model_or_deployment_name, + prompt, + response_format=ResponseFormat.TEXT, + temperature=1.0, + max_tokens=16 ): response_format = "json_object" if response_format.lower() == "json" else response_format prompt = f"{{% raw %}}{prompt}{{% endraw %}}" @@ -77,22 +77,25 @@ def get_question_type(testset_distribution) -> str: return next((key for key in testset_distribution.keys() if prob <= testset_distribution[key]), QuestionType.SIMPLE) -def get_suggested_answer_validation_res(connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, - max_tokens: int): +def get_suggested_answer_validation_res(connection, model_or_deployment_name, prompt, suggested_answer: str, + temperature: float, + max_tokens: int): rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens) return retrieve_verdict_and_print_reason( rsp=rsp, validate_obj_name=ValidateObj.SUGGESTED_ANSWER, validate_obj=suggested_answer ) -def get_question_validation_res(connection, model_or_deployment_name, prompt, question: str, response_format: ResponseFormat, temperature: float, - max_tokens: int): +def get_question_validation_res(connection, model_or_deployment_name, prompt, question: str, + response_format: ResponseFormat, temperature: float, + max_tokens: int): rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) -def get_text_trunk_validation_res(connection, model_or_deployment_name, prompt, context: str, response_format: ResponseFormat, temperature: float, - max_tokens: int): +def get_text_trunk_validation_res(connection, model_or_deployment_name, prompt, context: str, + response_format: ResponseFormat, temperature: float, + max_tokens: int): rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context) @@ -133,14 +136,17 @@ def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): def generate_question( - connection, model_or_deployment_name, question_type, seed_question, reasoning_prompt: str = None, conditional_prompt: str = None, temperature: float = None, - max_tokens: int = None + connection, model_or_deployment_name, question_type, seed_question, reasoning_prompt: str = None, + conditional_prompt: str = None, temperature: float = None, + max_tokens: int = None ): if question_type == QuestionType.SIMPLE: return seed_question elif question_type == QuestionType.REASONING: - return llm_call(connection, model_or_deployment_name, reasoning_prompt, temperature=temperature, max_tokens=max_tokens) + return llm_call(connection, model_or_deployment_name, reasoning_prompt, temperature=temperature, + max_tokens=max_tokens) elif question_type == QuestionType.CONDITIONAL: - return llm_call(connection, model_or_deployment_name, conditional_prompt, temperature=temperature, max_tokens=max_tokens) + return llm_call(connection, model_or_deployment_name, conditional_prompt, temperature=temperature, + max_tokens=max_tokens) else: raise Exception("Invalid question type.") diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py index 2f343e196e4..b264df63d88 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py @@ -8,14 +8,14 @@ @tool def validate_and_generate_seed_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, - validate_text_trunk_prompt: str, - seed_question_prompt: str, - context: str = None, - response_format: str = ResponseFormat.JSON, - temperature: float = 1.0, - max_tokens: int = 512 + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model_or_deployment_name: str, + validate_text_trunk_prompt: str, + seed_question_prompt: str, + context: str = None, + response_format: str = ResponseFormat.JSON, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given text chunk. @@ -25,7 +25,13 @@ def validate_and_generate_seed_question( dict: The generated seed question and text trunk validation result. """ validation_res = get_text_trunk_validation_res( - connection, model_or_deployment_name, validate_text_trunk_prompt, context, response_format, temperature, max_tokens + connection, + model_or_deployment_name, + validate_text_trunk_prompt, + context, + response_format, + temperature, + max_tokens ) is_valid_text_trunk = validation_res.pass_validation if not is_valid_text_trunk: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index a7ab9285626..51e64f95e02 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -11,12 +11,12 @@ # Please update the function name/signature per need @tool def validate_suggested_answer( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, - suggested_answer: str, - validate_suggested_answer_prompt: str, - temperature: float = 1.0, - max_tokens: int = 512 + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model_or_deployment_name: str, + suggested_answer: str, + validate_suggested_answer_prompt: str, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given ground truth. @@ -28,7 +28,8 @@ def validate_suggested_answer( return {"suggested_answer": "", "validation_res": None} validation_res = get_suggested_answer_validation_res(connection, model_or_deployment_name, - validate_suggested_answer_prompt, suggested_answer, temperature, max_tokens) + validate_suggested_answer_prompt, suggested_answer, + temperature, max_tokens) is_valid_gt = validation_res.pass_validation failed_reason = "" if not is_valid_gt: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py index 1c1b7689c6e..33b2699f524 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py @@ -8,13 +8,13 @@ @tool def validate_test_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, - question_info: dict, - # generate_context_prompt: str, - validate_question_prompt: str, - temperature: float = 1.0, - max_tokens: int = 512 + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model_or_deployment_name: str, + question_info: dict, + # generate_context_prompt: str, + validate_question_prompt: str, + temperature: float = 1.0, + max_tokens: int = 512 ): """ 1. Validates the given question. @@ -31,7 +31,8 @@ def validate_test_question( if question_type == QuestionType.SIMPLE: return question - validation_res = get_question_validation_res(connection, model_or_deployment_name, validate_question_prompt, question, temperature, max_tokens) + validation_res = get_question_validation_res(connection, model_or_deployment_name, validate_question_prompt, + question, temperature, max_tokens) is_valid_test_question = validation_res.pass_validation if not is_valid_test_question: print(f"Invalid test question: {question}") From 23d5076d6b6f93a7e2007c9abbadae5d27362e8c Mon Sep 17 00:00:00 2001 From: yalu4 Date: Tue, 30 Jan 2024 18:28:38 +0800 Subject: [PATCH 036/112] update to use score --- docs/how-to-guides/construct-test-data.md | 10 +- .../generate_test_data_flow/flow.dag.yaml | 22 ++-- .../generate_debug_info.py | 38 +++--- .../generate_suggested_answer.py | 4 +- .../generate_suggested_answer_prompt.jinja2 | 14 +-- .../score_text_trunk_prompt.jinja2 | 33 +++++ .../generate_test_data_flow/utils.py | 50 ++++++-- .../validate_and_generate_seed_question.py | 19 ++- .../validate_suggested_answer.py | 5 +- .../validate_suggested_answer_prompt.jinja2 | 32 ++--- .../validate_text_trunk_prompt.jinja2 | 34 ----- examples/gen_test_data/gen_test_data/run.py | 118 ++++++++++-------- .../gen_test_data/utils/analyze_data.py | 50 ++++++++ 13 files changed, 260 insertions(+), 169 deletions(-) create mode 100644 examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 delete mode 100644 examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 create mode 100644 examples/gen_test_data/gen_test_data/utils/analyze_data.py diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index fc8a3bb6944..0d2ed9d2c25 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -40,14 +40,14 @@ Enter `test_data_gen_local` folder, run below command to install required packag **Understand the prompts** - The test data construction flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, ground truths, etc., while validation prompts are used to verify the validity of the text trunk, generated question or ground truth. + The test data construction flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. - Generation prompts - *generate question prompt*: frame a question based on the given text trunk. - - *generate ground truth prompt*: generate ground truth for the question based on the given text trunk. + - *generate suggested answer prompt*: generate suggested answer for the question based on the given text trunk. - Validation prompts - - *validate text trunk prompt*: validate if the given text trunk is worthy of framing a question. + - *score text trunk prompt*: validate if the given text trunk is worthy of framing a question. If the score is lower than score_threshold, validation fails. - *validate seed/test question prompt*: validate if the generated question can be clearly understood. - - *validate ground truth*: validate if the generated ground truth is clear and certain. + - *validate suggested answer*: validate if the generated suggested answer is clear and certain. If the validation fails, the corresponding output would be an empty string so that the invalid data would not be incorporated into the final test data set. @@ -62,7 +62,7 @@ Enter `test_data_gen_local` folder, run below command to install required packag - Update the configurations in the `configs.ini` file. Here is a brief of introduction of each parameter: > // TODO: or move this part as comment in config ini? - *should_skip_doc_split*: Document split step can be reused. If you have already splitted the documents, and in next time you just want to generate the test data based on these document chunks, you can set the value as `True` to skip the document split step. - - *documents_folder*: the source path of text to be splitted into text trunks for question and ground truth generation. + - *documents_folder*: the source path of text to be splitted into text trunks for question and answer generation. - *document_chunk_size*: chunk size is used to determine the size of each text chunk > !Note: In this guidance, we leverage llama_index to do text chunking. There are two steps of document splitting: > diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index b2c589839b8..6ccc906b7d7 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -19,11 +19,11 @@ outputs: type: string reference: ${generate_debug_info.output} nodes: -- name: validate_text_trunk_prompt +- name: score_text_trunk_prompt type: prompt source: type: code - path: validate_text_trunk_prompt.jinja2 + path: score_text_trunk_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false @@ -58,11 +58,13 @@ nodes: type: code path: validate_and_generate_seed_question.py inputs: - connection: open-ai-connection + connection: model: gpt-4 - validate_text_trunk_prompt: ${validate_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} context: ${inputs.text_chunk} + score_text_trunk_prompt: ${score_text_trunk_prompt.output} + score_threshold: 4 + response_format: text use_variants: false - name: validate_and_generate_test_question type: python @@ -70,11 +72,11 @@ nodes: type: code path: validate_and_generate_test_question.py inputs: - connection: open-ai-connection + connection: model: gpt-4 validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output.question} - response_format: "" + response_format: text use_variants: false - name: validate_question_prompt type: prompt @@ -90,7 +92,7 @@ nodes: type: code path: validate_test_question.py inputs: - connection: open-ai-connection + connection: model: gpt-4 question_info: ${validate_and_generate_test_question.output} validate_question_prompt: ${validate_question_prompt.output} @@ -101,7 +103,7 @@ nodes: type: code path: generate_suggested_answer.py inputs: - connection: open-ai-connection + connection: context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} model: gpt-4 @@ -125,14 +127,14 @@ nodes: type: code path: validate_suggested_answer_prompt.jinja2 inputs: - suggested_answer: ${generate_suggested_answer.output} + answer: ${generate_suggested_answer.output} - name: validate_suggested_answer type: python source: type: code path: validate_suggested_answer.py inputs: - connection: open-ai-connection + connection: model: gpt-4 suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index d396d506126..8b657220c01 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -8,12 +8,12 @@ # Please update the function name/signature per need @tool def my_python_tool( - question_type: str, - text_trunk: str, - text_meta: dict = None, - validate_and_generate_seed_question_output: dict = None, - validate_and_generate_test_question_output: dict = None, - validate_suggested_answer_output: ValidationResult = None, + question_type: str, + text_trunk: str, + text_meta: dict = None, + validate_and_generate_seed_question_output: dict = None, + validate_and_generate_test_question_output: dict = None, + validate_suggested_answer_output: ValidationResult = None, ) -> dict: text_trunk_validation_res = validate_and_generate_seed_question_output["validation_res"] generated_seed_question = validate_and_generate_seed_question_output["question"] @@ -24,21 +24,22 @@ def my_python_tool( is_generation_success = generated_suggested_answer != "" is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None is_seed_question_valid = seed_question_validation_res.pass_validation if seed_question_validation_res else None - is_suggested_answer_valid = suggested_answer_validation_res.pass_validation \ - if suggested_answer_validation_res else None + is_suggested_answer_valid = ( + suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None + ) failed_step = "" failed_reason = "" if not is_generation_success: if is_text_trunk_valid is False: failed_step = ValidateObj.TEXT_TRUNK - failed_reason = text_trunk_validation_res.reason_if_failed + failed_reason = text_trunk_validation_res.reason elif is_seed_question_valid is False: failed_step = ValidateObj.QUESTION - failed_reason = seed_question_validation_res.reason_if_failed + failed_reason = seed_question_validation_res.reason elif is_suggested_answer_valid is False: - failed_step = ValidateObj.GROUND_TRUTH - failed_reason = suggested_answer_validation_res.reason_if_failed + failed_step = ValidateObj.SUGGESTED_ANSWER + failed_reason = suggested_answer_validation_res.reason return { "question_type": question_type, @@ -51,25 +52,20 @@ def my_python_tool( }, "generation_details": { "text_trunk": { + "score": text_trunk_validation_res.score if text_trunk_validation_res else None, + "reason": text_trunk_validation_res.reason if text_trunk_validation_res else None, "pass_validation": is_text_trunk_valid, - "reason_if_failed": text_trunk_validation_res.reason_if_failed - if is_text_trunk_valid is False - else None, }, "seed_question": { "generated_question": generated_seed_question, "pass_validation": is_seed_question_valid, - "reason_if_failed": seed_question_validation_res.reason_if_failed - if is_seed_question_valid is False - else None, + "reason": seed_question_validation_res.reason if seed_question_validation_res else None, }, # "test_question": {}, # placeholder for evolved questions like multi-context, reasoning, etc. "suggested_answer": { "generated_suggested_answer": generated_suggested_answer, "pass_validation": is_suggested_answer_valid, - "reason_if_failed": suggested_answer_validation_res.reason_if_failed - if is_suggested_answer_valid is False - else None, + "reason": suggested_answer_validation_res.reason if suggested_answer_validation_res else None, }, }, } diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index e83cd7d0124..b84a0550b91 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -15,10 +15,10 @@ def generate_suggested_answer( generate_suggested_answer_prompt: str, ): """ - Generates a ground truth based on the given prompts and context information. + Generates a suggested answer based on the given prompts and context information. Returns: - str: The generated ground truth. + str: The generated suggested answer. """ if question and context: return llm_call(connection, model, generate_suggested_answer_prompt) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 index e45fad222d7..bd3e928fdc3 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 @@ -1,12 +1,12 @@ system: -Provide the ground truth for the question using the information from the given context based on the following criteria: -1. The ground truth is correct and complete. -2. The ground truth is derived from the given context. -3. The ground truth can totally answer the question. -4. The ground truth should not use the words like "in the context". The ground truth should be enough to answer the question without the context. -5. If the ground truth for the question cannot be generated from the given context, just return empty string. +Provide the answer for the question using the information from the given context based on the following criteria: +1. The answer is correct and complete. +2. The answer is derived from the given context. +3. The answer can totally answer the question. +4. The answer should not use the words like "in the context". The answer should be enough to answer the question without the context. +5. If the answer for the question cannot be generated from the given context, just return empty string. user: question:{{question}} context:{{context}} -ground truth: +answer: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 new file mode 100644 index 00000000000..19995073ab6 --- /dev/null +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 @@ -0,0 +1,33 @@ +system: +Given a text trunk from a document as a context, complete the two following tasks and output a valid json format with the score and the reason. +Evaluate the provided context and assign a numerical score between 0 and 10 based on the following criteria: +1. Award a high score if: + (1) context delves into and explains concepts. + (2) context has information worthy of framing a question. +2. Award a lower score if if: + (1) context contains excessive references, acknowledgments, personal information. Some are acceptable, but too many will lower the score. + (2) context contains just punctuations or code snippet. + (3) context that is shorter than five words. + +user: +Output a JSON with both the score and the reason. The score and reason should totally based on the above criteria. Do not add any other criteria. The reason should be a string that explains why the score is given. +Here are some examples: +context: +"Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time." +output: +{ + "score": "6.0", + "reason": "The context contains information worthy of framing a question." +} + +context: +"Next step\n- Open the provided examples." +output: +{ + "score": "2.0", + "reason": "The context lacks information about the provided example and previous steps." +} + +context: +{{context}} +output: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index adcba803ec4..f06d7468d9b 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -30,13 +30,14 @@ class ResponseFormat: class ErrorMsg: - INVALID_JSON_FORMAT = "llm failed to return the verdict and reason in correct json format. Response: {0}" - INVALID_TEXT_TRUNK = "Skipping generating seed question due to invalid text chunk." + INVALID_JSON_FORMAT = "Invalid json format. Response: {0}" + INVALID_TEXT_TRUNK = "Skipping generating seed question due to invalid text chunk: {0}" INVALID_QUESTION = "Invalid seed question: {0}" INVALID_ANSWER = "Invalid answer: {0}" -ValidationResult = namedtuple("ValidationResult", ["pass_validation", "reason_if_failed"]) +ValidationResult = namedtuple("ValidationResult", ["pass_validation", "reason"]) +ScoreResult = namedtuple("ScoreResult", ["score", "reason", "pass_validation"]) def llm_call(connection, model, prompt, response_format=ResponseFormat.TEXT): @@ -71,19 +72,30 @@ def get_question_validation_res(connection, model, prompt, question: str, respon return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) -def get_text_trunk_validation_res(connection, model, prompt, context: str, response_format: ResponseFormat): +def get_text_trunk_score(connection, model, prompt, response_format: ResponseFormat, score_threshold: float): rsp = llm_call(connection, model, prompt, response_format) - return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.TEXT_TRUNK, validate_obj=context) + data = _load_json_rsp(rsp) + score_float = 0 + reason = "" + + if data and isinstance(data, dict) and "score" in data and "reason" in data: + # Extract the verdict and reason + score = data["score"].lower() + reason = data["reason"] + print(f"Score {ValidateObj.TEXT_TRUNK}: {score}\nReason: {reason}") + try: + score_float = float(score) + except ValueError: + reason = ErrorMsg.INVALID_JSON_FORMAT.format(rsp) + else: + reason = ErrorMsg.INVALID_JSON_FORMAT.format(rsp) + pass_validation = score_float >= score_threshold + + return ScoreResult(score_float, reason, pass_validation) def retrieve_verdict_and_print_reason(rsp: str, validate_obj_name: str, validate_obj: str) -> ValidationResult: - try: - # It is possible that even the response format is required as json, the response still contains ```json\n - rsp = re.sub(r"```json\n?|```", "", rsp) - data = json.loads(rsp) - except json.decoder.JSONDecodeError: - print(ErrorMsg.INVALID_JSON_FORMAT.format(rsp)) - data = None + data = _load_json_rsp(rsp) if data and isinstance(data, dict) and "verdict" in data and "reason" in data: # Extract the verdict and reason @@ -91,7 +103,7 @@ def retrieve_verdict_and_print_reason(rsp: str, validate_obj_name: str, validate reason = data["reason"] print(f"Is valid {validate_obj_name}: {verdict}\nReason: {reason}") if verdict == "yes": - return ValidationResult(True, "") + return ValidationResult(True, reason) elif verdict == "no": return ValidationResult(False, reason) else: @@ -100,6 +112,18 @@ def retrieve_verdict_and_print_reason(rsp: str, validate_obj_name: str, validate return ValidationResult(False, ErrorMsg.INVALID_JSON_FORMAT.format(rsp)) +def _load_json_rsp(rsp: str): + try: + # It is possible that even the response format is required as json, the response still contains ```json\n + rsp = re.sub(r"```json\n?|```", "", rsp) + data = json.loads(rsp) + except json.decoder.JSONDecodeError: + print(ErrorMsg.INVALID_JSON_FORMAT.format(rsp)) + data = None + + return data + + def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): testset_distribution = { QuestionType.SIMPLE: simple_ratio, diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py index 0b8a01be866..1736ef4da43 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py @@ -1,6 +1,6 @@ from typing import Union -from utils import ErrorMsg, ResponseFormat, get_text_trunk_validation_res, llm_call +from utils import ErrorMsg, ResponseFormat, get_text_trunk_score, llm_call from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -10,7 +10,8 @@ def validate_and_generate_seed_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, - validate_text_trunk_prompt: str, + score_text_trunk_prompt: str, + score_threshold: float, seed_question_prompt: str, context: str = None, response_format: str = ResponseFormat.JSON, @@ -22,14 +23,12 @@ def validate_and_generate_seed_question( Returns: dict: The generated seed question and text trunk validation result. """ - validation_res = get_text_trunk_validation_res( - connection, model, validate_text_trunk_prompt, context, response_format + text_trunk_score_res = get_text_trunk_score( + connection, model, score_text_trunk_prompt, response_format, score_threshold ) - is_valid_text_trunk = validation_res.pass_validation - if not is_valid_text_trunk: - print(ErrorMsg.INVALID_TEXT_TRUNK) - print(f"yaodebug: {validation_res}") - return {"question": "", "validation_res": validation_res} + if not text_trunk_score_res.pass_validation: + print(ErrorMsg.INVALID_TEXT_TRUNK.format(context)) + return {"question": "", "validation_res": text_trunk_score_res} seed_question = llm_call(connection, model, seed_question_prompt) - return {"question": seed_question, "validation_res": validation_res} + return {"question": seed_question, "validation_res": text_trunk_score_res} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 6cb7a282097..7a0d55a4073 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -25,8 +25,9 @@ def validate_suggested_answer( if not suggested_answer: return {"suggested_answer": "", "validation_res": None} - validation_res = get_suggested_answer_validation_res(connection, model, - validate_suggested_answer_prompt, suggested_answer) + validation_res = get_suggested_answer_validation_res( + connection, model, validate_suggested_answer_prompt, suggested_answer + ) is_valid_gt = validation_res.pass_validation failed_reason = "" if not is_valid_gt: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 index 429bc2313fe..ddb0a903374 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 @@ -1,41 +1,41 @@ system: -Given a ground truth, verdict if the provided ground truth is valid and provide the reason in valid json format. -The ground truth is not valid if the ground truth suggests that the context does not provide information or indicates uncertainty (such as 'I don't know'), it is deemed invalid. For any other case, the ground truth is considered valid. +Given an answer, verdict if the provided answer is valid and provide the reason in valid json format. +The answer is not valid if the answer suggests that the context does not provide information or indicates uncertainty (such as 'I don't know'), it is deemed invalid. For any other case, the answer is considered valid. user: Output a json format with the reason and verdict. Here are some examples: -suggested_answer: -The steps to build and install your tool package for use in VS Code extension are not provided in the context. answer: +The steps to build and install your tool package for use in VS Code extension are not provided in the context. +output: { - "reason":"The ground truth is invalid because it states that the context does not provide the necessary steps.", + "reason":"The answer is invalid because it states that the context does not provide the necessary steps.", "verdict":"no" } -suggested_answer: -The context does not provide specific information on what the possible provider values are in supported configs for a connection provider. answer: +The context does not provide specific information on what the possible provider values are in supported configs for a connection provider. +output: { - "reason":"The ground truth is invalid as it indicates that the context lacks specific information.", + "reason":"The answer is invalid as it indicates that the context lacks specific information.", "verdict":"no" } -suggested_answer: -I don't know. answer: +I don't know. +output: { - "reason":"The suggested_answer is invalid because it conveys don't know.", + "reason":"The answer is invalid because it conveys don't know.", "verdict":"no" } -suggested_answer: -The two essential components of an activate config in a node flow are `activate.when` and `activate.is`. answer: +The two essential components of an activate config in a node flow are `activate.when` and `activate.is`. +output: { - "reason":"The suggested_answer is valid because it is clear and true.", + "reason":"The answer is valid because it is clear and true.", "verdict":"yes" } -suggested_answer:{{suggested_answer}} -answer: +answer:{{answer}} +output: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 deleted file mode 100644 index 63a259ea4df..00000000000 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk_prompt.jinja2 +++ /dev/null @@ -1,34 +0,0 @@ -system: -Given a context, verdict if the provided context has information worthy of framing a question and give the reason. Output a JSON with the reason and verdict. -The verdict can be either "yes" or "no", following these guidelines: -1. Verdict "yes" if: - (1) context thoroughly delves into and explains concepts. - (2) context is complete and does not require additional information. - (3) context has information worthy of framing a question. -2. Verdict "no" if: - (1) context contains excessive references, acknowledgments, personal information, or other non-essential elements. - (2) context contains only punctuations or massive code snippet. - (3) context that is shorter than five words. - -user: -Output a JSON with both the reason and verdict. -Here are some examples: -context: -Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time. -answer: -{ - "verdict": "yes", - "reason": "The context contains information worthy of framing a question." -} - -context: -Next step\n- Open the provided examples. -answer: -{ - "verdict": "no", - "reason": "The context lacks information about the provided example and next steps of what." -} - -context: -{{context}} -answer: diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 604f9866724..50f8cff40ea 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,3 +1,4 @@ +import json import os from datetime import datetime @@ -15,19 +16,19 @@ if UTILS_PATH not in os.sys.path: os.sys.path.insert(0, UTILS_PATH) -from constants import TEXT_CHUNK, CONNECTIONS_TEMPLATE # noqa: E402 -from common import split_document, clean_data_and_save # noqa: E402 +from common import clean_data_and_save, split_document # noqa: E402 from components import clean_test_data_set, document_split # noqa: E402 +from constants import CONNECTIONS_TEMPLATE, TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") def batch_run_flow( - pf: PFClient, - flow_folder: str, - flow_input_data: str, - flow_batch_run_size: int, - connection_name: str = "azure_open_ai_connection", + pf: PFClient, + flow_folder: str, + flow_input_data: str, + flow_batch_run_size: int, + connection_name: str = "azure_open_ai_connection", ): logger.info("Start to submit the batch run.") base_run = pf.run( @@ -38,8 +39,10 @@ def batch_run_flow( "PF_WORKER_COUNT": str(flow_batch_run_size), "PF_BATCH_METHOD": "spawn", }, - connections={key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items()}, + connections={ + key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items() + }, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, ) @@ -54,8 +57,10 @@ def get_batch_run_output(pf: PFClient, base_run: Run): question = details["outputs.question"].tolist() suggested_answer = details["outputs.suggested_answer"].tolist() debug_info = details["outputs.debug_info"].tolist() - return [{"question": q, "suggested_answer": g, "debug_info": d} - for q, g, d in zip(question, suggested_answer, debug_info)] + return [ + {"question": q, "suggested_answer": g, "debug_info": d} + for q, g, d in zip(question, suggested_answer, debug_info) + ] def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): @@ -78,22 +83,27 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str ] ) def gen_test_data_pipeline( - data_input: Input, - flow_yml_path: str, - connection_name: str, - should_skip_doc_split: bool, - chunk_size=1024, - instance_count=1, - mini_batch_size="10kb", - max_concurrency_per_instance=2, + data_input: Input, + flow_yml_path: str, + connection_name: str, + should_skip_doc_split: bool, + chunk_size=1024, + instance_count=1, + mini_batch_size="10kb", + max_concurrency_per_instance=2, ): - data = data_input if should_skip_doc_split else document_split(documents_folder=data_input, - chunk_size=chunk_size).outputs.document_node_output + data = ( + data_input + if should_skip_doc_split + else document_split(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output + ) flow_node = load_component(flow_yml_path)( data=data, text_chunk="${data.text_chunk}", - connections={key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items()}, + connections={ + key: {"connection": value["connection"].format(connection_name=connection_name)} + for key, value in CONNECTIONS_TEMPLATE.items() + }, ) flow_node.mini_batch_size = mini_batch_size @@ -104,14 +114,14 @@ def gen_test_data_pipeline( def run_local( - documents_folder, - document_chunk_size, - document_nodes_file, - flow_folder, - flow_batch_run_size, - connection_name, - output_folder, - should_skip_split + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + flow_batch_run_size, + connection_name, + output_folder, + should_skip_split, ): text_chunks_path = document_nodes_file inner_folder = os.path.join(output_folder, datetime.now().strftime("%b-%d-%Y-%H-%M-%S")) @@ -131,24 +141,31 @@ def run_local( ) test_data_set = get_batch_run_output(pf, batch_run) + + # Store intermedian batch run output results + jsonl_str = "\n".join(map(json.dumps, test_data_set)) + intermedian_batch_run_res = os.path.join(inner_folder, "batch-run-result.jsonl") + with open(intermedian_batch_run_res, "wt") as text_file: + print(f"{jsonl_str}", file=text_file) + clean_data_output = os.path.join(inner_folder, "test-data.jsonl") clean_data_and_save(test_data_set, clean_data_output) def run_cloud( - documents_folder, - document_chunk_size, - document_nodes_file, - flow_folder, - connection_name, - subscription_id, - resource_group, - workspace_name, - aml_cluster, - prs_instance_count, - prs_mini_batch_size, - prs_max_concurrency_per_instance, - should_skip_split + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + connection_name, + subscription_id, + resource_group, + workspace_name, + aml_cluster, + prs_instance_count, + prs_mini_batch_size, + prs_max_concurrency_per_instance, + should_skip_split, ): ml_client = get_ml_client(subscription_id, resource_group, workspace_name) @@ -185,7 +202,7 @@ def run_cloud( + "Please check if you are under the wrong directory or the file is missing." ) - parser.add_argument('--cloud', action='store_true', help='cloud flag') + parser.add_argument("--cloud", action="store_true", help="cloud flag") parser.add_argument("--documents_folder", type=str, help="Documents folder path") parser.add_argument("--document_chunk_size", type=int, help="Document chunk size, default is 1024") parser.add_argument( @@ -208,8 +225,9 @@ def run_cloud( parser.add_argument("--aml_cluster", help="AzureML cluster name") parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") parser.add_argument("--prs_mini_batch_size", help="Parallel run step mini batch size") - parser.add_argument("--prs_max_concurrency_per_instance", type=int, - help="Parallel run step max concurrency per instance") + parser.add_argument( + "--prs_max_concurrency_per_instance", type=int, help="Parallel run step max concurrency per instance" + ) args = parser.parse_args() should_skip_split_documents = False @@ -232,7 +250,8 @@ def run_cloud( args.prs_instance_count, args.prs_mini_batch_size, args.prs_max_concurrency_per_instance, - should_skip_split_documents) + should_skip_split_documents, + ) else: run_local( args.documents_folder, @@ -242,4 +261,5 @@ def run_cloud( args.flow_batch_run_size, args.connection_name, args.output_folder, - should_skip_split_documents) + should_skip_split_documents, + ) diff --git a/examples/gen_test_data/gen_test_data/utils/analyze_data.py b/examples/gen_test_data/gen_test_data/utils/analyze_data.py new file mode 100644 index 00000000000..21cb0acbd6c --- /dev/null +++ b/examples/gen_test_data/gen_test_data/utils/analyze_data.py @@ -0,0 +1,50 @@ +import json +from argparse import ArgumentParser +from pathlib import Path + + +def analyze_batch_run_res(file_path): + gen_success_count = 0 + gen_failure_count = 0 + run_failed_count = 0 + gen_failure_steps = {} + gen_failure_reasons = {} + + with open(file_path, "r") as f: + for line in f: + data = json.loads(line) + + if data["debug_info"] == "(Failed)": + run_failed_count += 1 + continue + + if data["debug_info"]["generation_summary"]["success"]: + gen_success_count += 1 + else: + gen_failure_count += 1 + failed_step = data["debug_info"]["generation_summary"]["failed_step"] + failed_reason = data["debug_info"]["generation_summary"]["failed_reason"] + + if failed_step in gen_failure_steps: + gen_failure_steps[failed_step] += 1 + gen_failure_reasons[failed_step].append(failed_reason) + else: + gen_failure_steps[failed_step] = 1 + gen_failure_reasons[failed_step] = [failed_reason] + + print(f"Gen success count: {gen_success_count}") + print(f"Gen failure count: {gen_failure_count}") + print(f"Run failure count: {run_failed_count}") + print("Gen failures by step:") + for step, count in gen_failure_steps.items(): + print(f"{step}: {count}") + print("**Gen failures by reason:") + for step, reasons in gen_failure_reasons.items(): + print(f"{step}: {reasons}") + + +if __name__ == "__main__": + parser = ArgumentParser() + parser.add_argument("-f", "--jsonl_file", type=Path, required=True) + args = parser.parse_args() + analyze_batch_run_res(args.jsonl_file) From c840ad0a7f9c7d210117a9b61c70d0f669bc8bc1 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 22:00:48 +0800 Subject: [PATCH 037/112] update docs --- docs/how-to-guides/generate-test-data.md | 14 +++++++------- docs/how-to-guides/index.md | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index fc8a3bb6944..1863c908a63 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -1,4 +1,4 @@ -# How to construct test data based on documents +# How to generate test data based on documents This guide will instruct you on how to generate test data for RAG systems utilizing existing documents. Previously evaluating the performance of RAG systems required the creation of test data. This could be done manually, a process that required significant time and effort, or by purchasing pre-made test data, which could be costly. @@ -6,7 +6,7 @@ This test data generation process streamlines this by leveraging the capabilitie By following this guide, you will learn how to: 1. Customize the test data generation process by tuning flow prompts. -2. Generate high-quality test data quickly and easily by running a test data generation script. +2. Generate test data quickly and easily by running a test data generation script. **Supported file types** - .md - Markdown @@ -32,15 +32,15 @@ Enter `test_data_gen_local` folder, run below command to install required packag - .pdf - `pip install pypdf` - .ipynb - `pip install nbconvert` -- Run and tune test data construction flow - - Navigate to the [construct_test_data_flow folder](../../examples/test_data_gen/construct_test_data_flow/). Open the `flow.dag.yaml` to understand the structure of the data flow. Fill in necessary values like connections and model/deployment name. +- Create a test data generation flow + - Navigate to the [generate_test_data_flow folder](../../examples/gen_test_data/generate_test_data_flow/). Open the `flow.dag.yaml` to understand the structure of the data flow. Fill in necessary values like connections and model/deployment name. - Ensure the `flow.tools.json` is generated under `.promptflow` folder within the flow folder. - Check the guide [init-and-test-a-flow](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html) to test the flow. - [*Optional*] Customize your test data generation logic. Refer to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html) for more guidance. Once you updated the flow, ensure the flow can complete successfully before preceding to next steps to generate bulk data. **Understand the prompts** - The test data construction flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, ground truths, etc., while validation prompts are used to verify the validity of the text trunk, generated question or ground truth. + The test data generation flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, ground truths, etc., while validation prompts are used to verify the validity of the text trunk, generated question or ground truth. - Generation prompts - *generate question prompt*: frame a question based on the given text trunk. - *generate ground truth prompt*: generate ground truth for the question based on the given text trunk. @@ -57,7 +57,7 @@ Enter `test_data_gen_local` folder, run below command to install required packag - For the `gpt-4` model with version `0613`, use the response format `text`. - For the `gpt-4` model with version `1106`, use the response format `json`. -- Run data generation script +## Generate test data at local - Enter [test_data_gen_local folder](../../examples/test_data_gen/test_data_gen_local). - Update the configurations in the `configs.ini` file. Here is a brief of introduction of each parameter: > // TODO: or move this part as comment in config ini? @@ -79,7 +79,7 @@ Enter `test_data_gen_local` folder, run below command to install required packag - The generated test data will be a data jsonl file located in the path you configured in `config.ini`. -## Cloud +## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in pipeline. - Prerequisites Enter `test_data_gen_pipeline` folder, run below command to install required packages. diff --git a/docs/how-to-guides/index.md b/docs/how-to-guides/index.md index 3f41006f4a6..4a8282d937a 100644 --- a/docs/how-to-guides/index.md +++ b/docs/how-to-guides/index.md @@ -18,6 +18,6 @@ manage-runs set-global-configs develop-a-tool/index process-image-in-flow -construct-test-data +generate-test-data faq ``` From ab0cc14f7ed42d272616c3ad327b4480c71d51c8 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Tue, 30 Jan 2024 22:15:57 +0800 Subject: [PATCH 038/112] refine a simple doc version --- docs/how-to-guides/generate-test-data.md | 65 ++++++++++++------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 29a9d4d139b..b2a8b0ae5d0 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -21,7 +21,7 @@ By following this guide, you will learn how to: ## Quick start - Install required packages -Enter `test_data_gen_local` folder, run below command to install required packages. +Enter `gen_test_data` folder, run below command to install required packages. ```bash pip install -r requirements.txt ``` @@ -40,7 +40,7 @@ Enter `test_data_gen_local` folder, run below command to install required packag **Understand the prompts** - The test data construction flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. + The test data generation flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. - Generation prompts - *generate question prompt*: frame a question based on the given text trunk. - *generate suggested answer prompt*: generate suggested answer for the question based on the given text trunk. @@ -58,39 +58,38 @@ Enter `test_data_gen_local` folder, run below command to install required packag - For the `gpt-4` model with version `1106`, use the response format `json`. ## Generate test data at local - - Enter [test_data_gen_local folder](../../examples/test_data_gen/test_data_gen_local). - - Update the configurations in the `configs.ini` file. Here is a brief of introduction of each parameter: - > // TODO: or move this part as comment in config ini? - - *should_skip_doc_split*: Document split step can be reused. If you have already splitted the documents, and in next time you just want to generate the test data based on these document chunks, you can set the value as `True` to skip the document split step. - - *documents_folder*: the source path of text to be splitted into text trunks for question and answer generation. - - *document_chunk_size*: chunk size is used to determine the size of each text chunk - > !Note: In this guidance, we leverage llama_index to do text chunking. There are two steps of document splitting: - > - > a. Each document would be splitted roughly based on different document file types. Markdown file would be splitted by Heading, pdf file would be splitted by pages. - > b. For each splitted document chunk, it would get further splitted by chunk size. Chunk size may not seem to work if the text token size is smaller than chunk size. - - *document_nodes_output_path*: //TODO: make it a default folder without need to configure. - - *flow_folder*: //TODO: can we use relative path so that there is no need to configure the flow folder path either. - - *connection_name*: //TODO: do we need to provide the option to override the connection in script. - - *test_data_output_path*: output path of generated test data set. - - After configuration, run the following command to generate the test data set: - ```bash - python run_test_data_gen.py - ``` - - The generated test data will be a data jsonl file located in the path you configured in `config.ini`. +- Enter [gen_test_data_folder](../../examples/gen_test_data_gen). +- Install the required packages. + ``` + pip install -r requirements.txt + ``` +- Run command and update the `COMMON` and `LOCAL` configurations in the `configs.ini` file + ``` + cp config.ini.example config.ini + ``` + +- After configuration, run the following command to generate the test data set: + ```bash + python -m gen_test_data.run + ``` +- The generated test data will be a data jsonl file located in the path you configured in `config.ini`. ## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in pipeline. -- Prerequisites - Enter `test_data_gen_pipeline` folder, run below command to install required packages. - ```bash - pip install -r requirements.txt - ``` +- Enter [gen_test_data_folder](../../examples/gen_test_data_gen) +- Install the required packages. + ``` + pip install -r requirements_cloud.txt + ``` -- Enter [test_data_gen_pipeline folder](../../examples/test_data_gen/test_data_gen_pipeline) - - Update configs in `configs.ini` - - After configuration, run below command to gen test data set. - ```bash - python run_test_data_gen_pipeline.py - ``` - - The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. +- Run command and update the `COMMON` and `CLOUD` configurations in the `configs.ini` file + ``` + cp config.ini.example config.ini + ``` +- After configuration, run the following command to generate the test data set: + ```bash + python -m gen_test_data.run --cloud + ``` + +- The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. From 90ef65d97233503666870ddf171c02bbf2c88503 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Wed, 31 Jan 2024 14:39:18 +0800 Subject: [PATCH 039/112] update docs --- docs/how-to-guides/generate-test-data.md | 114 +++++++++++------------ 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index b2a8b0ae5d0..0afe4a50795 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -1,69 +1,67 @@ # How to generate test data based on documents -This guide will instruct you on how to generate test data for RAG systems utilizing existing documents. -Previously evaluating the performance of RAG systems required the creation of test data. This could be done manually, a process that required significant time and effort, or by purchasing pre-made test data, which could be costly. +This guide will instruct you on how to generate test data for RAG systems using pre-existing documents. +This approach eliminates the need for manual data creation, which is typically time-consuming and labor-intensive, or the expensive option of purchasing pre-packaged test data. +By leveraging the capabilities of llm, this guide streamlines the test data generation process, making it more efficient and cost-effective. -This test data generation process streamlines this by leveraging the capabilities of llm to automatically generate the test data. This not only reduces the effort required but also eliminates the need for additional expenditures. -By following this guide, you will learn how to: -1. Customize the test data generation process by tuning flow prompts. -2. Generate test data quickly and easily by running a test data generation script. +## Prerequisites -**Supported file types** -- .md - Markdown -- .docx - Microsoft Word -- .pdf - Portable Document Format -- .ipynb - Jupyter Notebook +1. Prepare documents. The test data generator supports the following file types: + - .md - Markdown + - .docx - Microsoft Word + - .pdf - Portable Document Format + - .ipynb - Jupyter Notebook -**Limitations** + **Limitations:** -- While the test data generator works well with standard documents, it may face challenges with API introduction documents or reference documents. -- Additionally, it may not function effectively for non-Latin characters, such as Chinese. These limitations may be due to the text loader capabilities such as pypdf. + - While the test data generator works well with standard documents, it may face challenges with API introduction documents or reference documents. + - The test data generator may not function effectively for non-Latin characters, such as Chinese. These limitations may be due to the text loader capabilities, such as `pypdf`. -## Quick start -- Install required packages -Enter `gen_test_data` folder, run below command to install required packages. - ```bash - pip install -r requirements.txt - ``` - - For specific document file types, you will need to install extra packages: - > !Note: This package requirement may be outdated. In this process, we utilize llama index `SimpleDirectoryReador`. For the most recent information, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). - - .docx - `pip install docx2txt` - - .pdf - `pip install pypdf` - - .ipynb - `pip install nbconvert` - -- Create a test data generation flow - - Navigate to the [generate_test_data_flow folder](../../examples/gen_test_data/generate_test_data_flow/). Open the `flow.dag.yaml` to understand the structure of the data flow. Fill in necessary values like connections and model/deployment name. - - Ensure the `flow.tools.json` is generated under `.promptflow` folder within the flow folder. - - Check the guide [init-and-test-a-flow](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html) to test the flow. - - [*Optional*] Customize your test data generation logic. Refer to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html) for more guidance. Once you updated the flow, ensure the flow can complete successfully before preceding to next steps to generate bulk data. +2. Go to the [gen_test_data](../../examples/gen_test_data) folder and install required packages. + - Run in local: `pip install -r requirements.txt` + - Run in cloud: `pip install -r requirements_cloud.txt` - **Understand the prompts** - - The test data generation flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. - - Generation prompts - - *generate question prompt*: frame a question based on the given text trunk. - - *generate suggested answer prompt*: generate suggested answer for the question based on the given text trunk. - - Validation prompts - - *score text trunk prompt*: validate if the given text trunk is worthy of framing a question. If the score is lower than score_threshold, validation fails. - - *validate seed/test question prompt*: validate if the generated question can be clearly understood. - - *validate suggested answer*: validate if the generated suggested answer is clear and certain. - - If the validation fails, the corresponding output would be an empty string so that the invalid data would not be incorporated into the final test data set. + For specific document file types, you will need to install extra packages: + > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + - .docx - `pip install docx2txt` + - .pdf - `pip install pypdf` + - .ipynb - `pip install nbconvert` + +3. Install VSCode extension and create connections refer to [Create a connection](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) + + +## Create a test data generation flow + - Open the [generate_test_data_flow](../../examples/gen_test_data/generate_test_data_flow/) folder in VSCode. + + + - [*Optional*] Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). + + **Understand the prompts** + + The test data generation flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. + - Generation prompts + - *generate question prompt*: frame a question based on the given text trunk. + - *generate suggested answer prompt*: generate suggested answer for the question based on the given text trunk. + - Validation prompts + - *score text trunk prompt*: validate if the given text trunk is worthy of framing a question. If the score is lower than score_threshold, validation fails. + - *validate seed/test question prompt*: validate if the generated question can be clearly understood. + - *validate suggested answer*: validate if the generated suggested answer is clear and certain. + + If the validation fails, the corresponding output would be an empty string so that the invalid data would not be incorporated into the final test data set. + - **Set the appropriate model and corresponding response format**: - The `gpt-4` model is recommended. The default prompt may yield better results with this model compared to the gpt-3 series. - - For the `gpt-4` model with version `0613`, use the response format `text`. - - For the `gpt-4` model with version `1106`, use the response format `json`. + - Fill in the necessary flow/node inputs, and run the flow in VSCode refering to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + **Set the appropriate model and corresponding response format.** The `gpt-4` model is recommended. The default prompt may yield better results with this model compared to the gpt-3 series. + - For the `gpt-4` model with version `0613`, use the response format `text`. + - For the `gpt-4` model with version `1106`, use the response format `json`. + + ## Generate test data at local -- Enter [gen_test_data_folder](../../examples/gen_test_data_gen). -- Install the required packages. - ``` - pip install -r requirements.txt - ``` -- Run command and update the `COMMON` and `LOCAL` configurations in the `configs.ini` file +- Navigate to [gen_test_data](../../examples/gen_test_data_gen) folder. + +- Run command to copy `config.ini.example` and update the `COMMON` and `LOCAL` configurations in the `configs.ini` file ``` cp config.ini.example config.ini ``` @@ -77,13 +75,9 @@ Enter `gen_test_data` folder, run below command to install required packages. ## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in pipeline. -- Enter [gen_test_data_folder](../../examples/gen_test_data_gen) -- Install the required packages. - ``` - pip install -r requirements_cloud.txt - ``` +- Navigate to [gen_test_data](../../examples/gen_test_data_gen) folder. -- Run command and update the `COMMON` and `CLOUD` configurations in the `configs.ini` file +- Run command to copy `config.ini.example` and update the `COMMON` and `CLOUD` configurations in the `configs.ini` file ``` cp config.ini.example config.ini ``` From 762f1a674ff8577d2e8a63172c1567acbfb51f4e Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Thu, 1 Feb 2024 11:36:31 +0800 Subject: [PATCH 040/112] improve data gen flow (#1897) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --- .../generate_test_data_flow/flow.dag.yaml | 60 ++++++------------- .../score_text_trunk_prompt.jinja2 | 6 +- .../seed_question_prompt.jinja2 | 31 ++++------ .../validate_question_prompt.jinja2 | 15 +++-- .../validate_suggested_answer_prompt.jinja2 | 6 +- .../gen_test_data/utils/constants.py | 1 - 6 files changed, 45 insertions(+), 74 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 70a00db4b97..b10679daafb 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -5,16 +5,14 @@ inputs: text_chunk: type: string is_chat_input: false - default: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born - theoretical physicist who is widely held to be one of the greatest and - most influential scientists of all time. + default: "" text_meta: type: string default: "{}" outputs: question: type: string - reference: ${validate_test_question.output} + reference: ${validate_and_generate_test_question.output.question} suggested_answer: type: string reference: ${validate_suggested_answer.output.suggested_answer} @@ -37,6 +35,7 @@ nodes: path: validate_question_prompt.jinja2 inputs: question: ${validate_and_generate_seed_question.output.question} + context: ${inputs.text_chunk} use_variants: false - name: seed_question_prompt type: prompt @@ -53,7 +52,7 @@ nodes: path: generate_suggested_answer_prompt.jinja2 inputs: context: ${inputs.text_chunk} - question: ${validate_test_question.output} + question: ${validate_and_generate_test_question.output.question} use_variants: false - name: validate_and_generate_seed_question type: python @@ -61,15 +60,14 @@ nodes: type: code path: validate_and_generate_seed_question.py inputs: - connection: - model_or_deployment_name: gpt-4 + model_or_deployment_name: "" score_text_trunk_prompt: ${score_text_trunk_prompt.output} seed_question_prompt: ${seed_question_prompt.output} context: ${inputs.text_chunk} score_threshold: 4 response_format: text - temperature: 1 - max_tokens: 512 + temperature: 0.2 + max_tokens: "" use_variants: false - name: validate_and_generate_test_question type: python @@ -77,34 +75,12 @@ nodes: type: code path: validate_and_generate_test_question.py inputs: - connection: - model_or_deployment_name: gpt-4 + model_or_deployment_name: "" validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${validate_and_generate_seed_question.output.question} response_format: text - temperature: 1 - max_tokens: 512 - use_variants: false -- name: validate_question_prompt - type: prompt - source: - type: code - path: validate_question_prompt.jinja2 - inputs: - question: ${validate_and_generate_test_question.output.question} - use_variants: false -- name: validate_test_question - type: python - source: - type: code - path: validate_test_question.py - inputs: - connection: - model_or_deployment_name: gpt-4 - question_info: ${validate_and_generate_test_question.output} - validate_question_prompt: ${validate_question_prompt.output} - temperature: 1 - max_tokens: 512 + temperature: 0.2 + max_tokens: "" use_variants: false - name: generate_suggested_answer type: python @@ -112,13 +88,12 @@ nodes: type: code path: generate_suggested_answer.py inputs: - connection: context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} - question: ${validate_test_question.output} - model_or_deployment_name: gpt-4 - temperature: 1 - max_tokens: 512 + question: ${validate_and_generate_test_question.output.question} + model_or_deployment_name: "" + temperature: 0.2 + max_tokens: "" use_variants: false - name: generate_debug_info type: python @@ -145,9 +120,8 @@ nodes: type: code path: validate_suggested_answer.py inputs: - connection: - model_or_deployment_name: gpt-4 + model_or_deployment_name: "" suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} - temperature: 1 - max_tokens: 512 + temperature: 0.2 + max_tokens: "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 index 19995073ab6..df143012ad5 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 @@ -1,4 +1,5 @@ -system: +# system: + Given a text trunk from a document as a context, complete the two following tasks and output a valid json format with the score and the reason. Evaluate the provided context and assign a numerical score between 0 and 10 based on the following criteria: 1. Award a high score if: @@ -9,7 +10,8 @@ Evaluate the provided context and assign a numerical score between 0 and 10 base (2) context contains just punctuations or code snippet. (3) context that is shorter than five words. -user: +# user: + Output a JSON with both the score and the reason. The score and reason should totally based on the above criteria. Do not add any other criteria. The reason should be a string that explains why the score is given. Here are some examples: context: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 index 3db02e1c380..dcc23077e41 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 @@ -1,27 +1,16 @@ -system: +# system: + Your task is to formulate a question from given context satisfying the rules given below: -1.The question should make sense to humans even when read without the given context. -2.The question should be fully answered from the given context. -3.The question should better be framed from the overall context, serving as a general question, rather than just framed from a part of context sentences. -4.The answer to the question should not contain any links. -5.The question should be of moderate difficulty. -6.The question must be reasonable and must be understood and responded by humans. -7.Do no use phrases like 'provided context',etc in the question -8.Avoid framing question using word "and" that can be decomposed into more than one question. -9.The question should not contain more than 20 words, make of use of abbreviation wherever possible. -user: -Here are some examples: -context: -If you do not provide one, the system uses a default icon. -question: -What does the system use if you do not provide an icon? - -context: -Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon. -question: -What is the use of a tool icon when developing your own tool package? +1.The question should better be framed from the overall context, serving as a general question, rather than just framed from some details. +2.The question should be specific and answerable from the given context. +3.The question must be reasonable and must be understood and responded by humans. +4.The question should not contains phrases like 'provided context' in the question. +5.The question should not contain any links. +6.The question should not contain more than 20 words, use abbreviation wherever possible. +# user: context: {{context}} + question: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 index 7750f97ea56..5eaa79ac56c 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 @@ -1,8 +1,10 @@ -system: -Determine if the given question can be clearly understood and give the reason. Output a valid json with reason and verdict. +# system: + +Verdict a question based on following rules: + +1. If there are acronyms or terms in the question, then please check if they exist in the given context. If no, verdict no. If yes, check if other rules are satisfied. +2. Determine if the given question can be clearly understood and give the reason. Output a valid json with reason and verdict. -user: -Output a valid json with reason and verdict. Here are some examples: question: What is the discovery about space? answer: @@ -53,5 +55,8 @@ answer: "verdict": "no" } -question:{{question}} +# user: +context: {{context}} + +question: {{question}} answer: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 index ddb0a903374..f01dca227ed 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 @@ -1,8 +1,10 @@ -system: +# system: + Given an answer, verdict if the provided answer is valid and provide the reason in valid json format. The answer is not valid if the answer suggests that the context does not provide information or indicates uncertainty (such as 'I don't know'), it is deemed invalid. For any other case, the answer is considered valid. -user: +# user: + Output a json format with the reason and verdict. Here are some examples: answer: diff --git a/examples/gen_test_data/gen_test_data/utils/constants.py b/examples/gen_test_data/gen_test_data/utils/constants.py index bc9d55e6eb0..b3bf62714e9 100644 --- a/examples/gen_test_data/gen_test_data/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/utils/constants.py @@ -24,7 +24,6 @@ CONNECTIONS_TEMPLATE = { "validate_and_generate_seed_question": {"connection": "{connection_name}"}, "validate_and_generate_test_question": {"connection": "{connection_name}"}, - "validate_test_question": {"connection": "{connection_name}"}, "generate_suggested_answer": {"connection": "{connection_name}"}, "validate_suggested_answer": {"connection": "{connection_name}"} } From b34e1985e7a0e7c36973fa86684bfd1901a351f4 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:02:02 +0800 Subject: [PATCH 041/112] Update flow structure (#1907) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. ![image](https://github.com/microsoft/promptflow/assets/46446115/298a0f5f-9842-47e2-9900-22c862f4fb19) --------- Co-authored-by: yalu4 --- .../generate_test_data_flow/flow.dag.yaml | 53 +++++++++++-------- .../generate_debug_info.py | 20 +++---- .../generate_question.py | 31 +++++++++++ ...jinja2 => generate_question_prompt.jinja2} | 0 ..._test_question.py => validate_question.py} | 33 +++++------- .../validate_test_question.py | 41 -------------- ...eed_question.py => validate_text_trunk.py} | 17 +++--- .../gen_test_data/utils/constants.py | 18 +++---- 8 files changed, 98 insertions(+), 115 deletions(-) create mode 100644 examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py rename examples/gen_test_data/gen_test_data/generate_test_data_flow/{seed_question_prompt.jinja2 => generate_question_prompt.jinja2} (100%) rename examples/gen_test_data/gen_test_data/generate_test_data_flow/{validate_and_generate_test_question.py => validate_question.py} (54%) delete mode 100644 examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py rename examples/gen_test_data/gen_test_data/generate_test_data_flow/{validate_and_generate_seed_question.py => validate_text_trunk.py} (61%) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index b10679daafb..764124b61c7 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -12,7 +12,7 @@ inputs: outputs: question: type: string - reference: ${validate_and_generate_test_question.output.question} + reference: ${validate_question.output.question} suggested_answer: type: string reference: ${validate_suggested_answer.output.suggested_answer} @@ -28,20 +28,20 @@ nodes: inputs: context: ${inputs.text_chunk} use_variants: false -- name: validate_seed_question_prompt +- name: validate_question_prompt type: prompt source: type: code path: validate_question_prompt.jinja2 inputs: - question: ${validate_and_generate_seed_question.output.question} + question: ${generate_question.output} context: ${inputs.text_chunk} use_variants: false -- name: seed_question_prompt +- name: generate_question_prompt type: prompt source: type: code - path: seed_question_prompt.jinja2 + path: generate_question_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false @@ -52,35 +52,32 @@ nodes: path: generate_suggested_answer_prompt.jinja2 inputs: context: ${inputs.text_chunk} - question: ${validate_and_generate_test_question.output.question} + question: ${validate_question.output.question} use_variants: false -- name: validate_and_generate_seed_question +- name: generate_question type: python source: type: code - path: validate_and_generate_seed_question.py + path: generate_question.py inputs: model_or_deployment_name: "" - score_text_trunk_prompt: ${score_text_trunk_prompt.output} - seed_question_prompt: ${seed_question_prompt.output} - context: ${inputs.text_chunk} - score_threshold: 4 - response_format: text + context: ${validate_text_trunk.output.context} temperature: 0.2 max_tokens: "" + generate_question_prompt: ${generate_question_prompt.output} use_variants: false -- name: validate_and_generate_test_question +- name: validate_question type: python source: type: code - path: validate_and_generate_test_question.py + path: validate_question.py inputs: model_or_deployment_name: "" - validate_seed_question_prompt: ${validate_seed_question_prompt.output} - seed_question: ${validate_and_generate_seed_question.output.question} - response_format: text + response_format: json_object temperature: 0.2 max_tokens: "" + generated_question: ${generate_question.output} + validate_question_prompt: ${validate_question_prompt.output} use_variants: false - name: generate_suggested_answer type: python @@ -90,7 +87,7 @@ nodes: inputs: context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} - question: ${validate_and_generate_test_question.output.question} + question: ${validate_question.output.question} model_or_deployment_name: "" temperature: 0.2 max_tokens: "" @@ -101,12 +98,12 @@ nodes: type: code path: generate_debug_info.py inputs: - question_type: ${validate_and_generate_test_question.output.question_type} + question_type: ${validate_question.output.question_type} text_trunk: ${inputs.text_chunk} text_meta: ${inputs.text_meta} - validate_and_generate_seed_question_output: ${validate_and_generate_seed_question.output} - validate_and_generate_test_question_output: ${validate_and_generate_test_question.output} validate_suggested_answer_output: ${validate_suggested_answer.output} + text_trunk_validation_res: ${validate_text_trunk.output.validation_res} + validate_question_output: ${validate_question.output} - name: validate_suggested_answer_prompt type: prompt source: @@ -125,3 +122,15 @@ nodes: validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} temperature: 0.2 max_tokens: "" +- name: validate_text_trunk + type: python + source: + type: code + path: validate_text_trunk.py + inputs: + score_text_trunk_prompt: ${score_text_trunk_prompt.output} + context: ${inputs.text_chunk} + score_threshold: 4 + model_or_deployment_name: "" + temperature: 0.2 + max_tokens: "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index 8b657220c01..1a610cc6e4a 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -11,19 +11,19 @@ def my_python_tool( question_type: str, text_trunk: str, text_meta: dict = None, - validate_and_generate_seed_question_output: dict = None, - validate_and_generate_test_question_output: dict = None, - validate_suggested_answer_output: ValidationResult = None, + text_trunk_validation_res: ValidationResult = None, + validate_question_output: dict = None, + validate_suggested_answer_output: dict = None, ) -> dict: - text_trunk_validation_res = validate_and_generate_seed_question_output["validation_res"] - generated_seed_question = validate_and_generate_seed_question_output["question"] - seed_question_validation_res = validate_and_generate_test_question_output["validation_res"] + generated_question = validate_question_output["question"] + question_validation_res = validate_question_output["validation_res"] + generated_suggested_answer = validate_suggested_answer_output["suggested_answer"] suggested_answer_validation_res = validate_suggested_answer_output["validation_res"] is_generation_success = generated_suggested_answer != "" is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None - is_seed_question_valid = seed_question_validation_res.pass_validation if seed_question_validation_res else None + is_seed_question_valid = question_validation_res.pass_validation if question_validation_res else None is_suggested_answer_valid = ( suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None ) @@ -36,7 +36,7 @@ def my_python_tool( failed_reason = text_trunk_validation_res.reason elif is_seed_question_valid is False: failed_step = ValidateObj.QUESTION - failed_reason = seed_question_validation_res.reason + failed_reason = question_validation_res.reason elif is_suggested_answer_valid is False: failed_step = ValidateObj.SUGGESTED_ANSWER failed_reason = suggested_answer_validation_res.reason @@ -57,9 +57,9 @@ def my_python_tool( "pass_validation": is_text_trunk_valid, }, "seed_question": { - "generated_question": generated_seed_question, + "generated_question": generated_question, "pass_validation": is_seed_question_valid, - "reason": seed_question_validation_res.reason if seed_question_validation_res else None, + "reason": question_validation_res.reason if question_validation_res else None, }, # "test_question": {}, # placeholder for evolved questions like multi-context, reasoning, etc. "suggested_answer": { diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py new file mode 100644 index 00000000000..172bec2fb18 --- /dev/null +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py @@ -0,0 +1,31 @@ +from typing import Union + +from utils import llm_call + +from promptflow import tool +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + + +@tool +def generate_seed_question( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model_or_deployment_name: str, + generate_question_prompt: str, + context: str = None, + temperature: float = 1.0, + max_tokens: int = 512, +): + """ + Generates a question based on the given context. + + Returns: + dict: The generated seed question. + """ + # text trunk is not valid, just skip test data gen. + if not context: + return "" + + seed_question = llm_call( + connection, model_or_deployment_name, generate_question_prompt, temperature=temperature, max_tokens=max_tokens + ) + return seed_question diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/seed_question_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py similarity index 54% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index f96dc7c7640..6ef7d7e9411 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_test_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -7,19 +7,14 @@ @tool -def validate_and_generate_test_question( +def validate_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], model_or_deployment_name: str, - seed_question: str, - # reasoning_prompt: str, - # conditional_prompt: str, - validate_seed_question_prompt: str, - # simple_ratio: float = 0.5, - # reasoning_ratio: float = 0.25, - # conditional_ratio: float = 0.25, + generated_question: str, + validate_question_prompt: str, response_format: str = ResponseFormat.JSON, temperature: float = 1.0, - max_tokens: int = 512 + max_tokens: int = 512, ): """ 1. Validates the given seed question. @@ -29,27 +24,27 @@ def validate_and_generate_test_question( dict: The generated test question and its type. """ # text trunk is not valid, seed question not generated. - if not seed_question: + if not generated_question: return {"question": "", "question_type": "", "validation_res": None} validation_res = get_question_validation_res( - connection, model_or_deployment_name, validate_seed_question_prompt, seed_question, response_format, temperature, max_tokens + connection, + model_or_deployment_name, + validate_question_prompt, + generated_question, + response_format, + temperature, + max_tokens, ) is_valid_seed_question = validation_res.pass_validation question = "" question_type = "" failed_reason = "" if not is_valid_seed_question: - failed_reason = ErrorMsg.INVALID_QUESTION.format(seed_question) + failed_reason = ErrorMsg.INVALID_QUESTION.format(generated_question) print(failed_reason) else: - # TODO: add multi_context prompt (p3) - # TODO: add reasoning prompt and conditional prompt (p4) - # testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) - - # question_type = get_question_type(testset_distribution) - # question = generate_question(connection, model_or_deployment_name, question_type, seed_question) - question = seed_question + question = generated_question question_type = QuestionType.SIMPLE return {"question": question, "question_type": question_type, "validation_res": validation_res} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py deleted file mode 100644 index 33b2699f524..00000000000 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_test_question.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import Union - -from utils import QuestionType, get_question_validation_res - -from promptflow import tool -from promptflow.connections import AzureOpenAIConnection, OpenAIConnection - - -@tool -def validate_test_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, - question_info: dict, - # generate_context_prompt: str, - validate_question_prompt: str, - temperature: float = 1.0, - max_tokens: int = 512 -): - """ - 1. Validates the given question. - 2. Generates a context based on the given prompts and question information. - - Returns: - str: The generated context. - """ - question = question_info["question"] - question_type = question_info["question_type"] - if not question: - return "" - # if question type is simple, the question is validated, no need to validate again. - if question_type == QuestionType.SIMPLE: - return question - - validation_res = get_question_validation_res(connection, model_or_deployment_name, validate_question_prompt, - question, temperature, max_tokens) - is_valid_test_question = validation_res.pass_validation - if not is_valid_test_question: - print(f"Invalid test question: {question}") - return "" - else: - return question diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py similarity index 61% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py index 60605403820..90bb4804bd7 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_and_generate_seed_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py @@ -1,29 +1,27 @@ from typing import Union -from utils import ErrorMsg, ResponseFormat, get_text_trunk_score, llm_call +from utils import ErrorMsg, ResponseFormat, get_text_trunk_score from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool -def validate_and_generate_seed_question( +def validate_text_trunk( connection: Union[OpenAIConnection, AzureOpenAIConnection], model_or_deployment_name: str, score_text_trunk_prompt: str, score_threshold: float, - seed_question_prompt: str, context: str = None, response_format: str = ResponseFormat.JSON, temperature: float = 1.0, max_tokens: int = 512, ): """ - 1. Validates the given text chunk. - 2. Generates a seed question based on the given prompts. + Validates the given text chunk. If the validation fails, return an empty context and the validation result. Returns: - dict: The generated seed question and text trunk validation result. + dict: Text trunk context and its validation result. """ text_trunk_score_res = get_text_trunk_score( connection, @@ -36,9 +34,6 @@ def validate_and_generate_seed_question( ) if not text_trunk_score_res.pass_validation: print(ErrorMsg.INVALID_TEXT_TRUNK.format(context)) - return {"question": "", "validation_res": text_trunk_score_res} + return {"context": "", "validation_res": text_trunk_score_res} - seed_question = llm_call( - connection, model_or_deployment_name, seed_question_prompt, temperature=temperature, max_tokens=max_tokens - ) - return {"question": seed_question, "validation_res": text_trunk_score_res} + return {"context": context, "validation_res": text_trunk_score_res} diff --git a/examples/gen_test_data/gen_test_data/utils/constants.py b/examples/gen_test_data/gen_test_data/utils/constants.py index b3bf62714e9..b8f67a943c8 100644 --- a/examples/gen_test_data/gen_test_data/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/utils/constants.py @@ -9,21 +9,15 @@ "dependencies": [ "python=3.10.12", "pip=23.2.1", - { - "pip": [ - "mldesigner==0.1.0b17", - "llama_index", - "docx2txt", - "promptflow" - ] - }, + {"pip": ["mldesigner==0.1.0b17", "llama_index", "docx2txt", "promptflow"]}, ], - } + }, ) CONNECTIONS_TEMPLATE = { - "validate_and_generate_seed_question": {"connection": "{connection_name}"}, - "validate_and_generate_test_question": {"connection": "{connection_name}"}, + "validate_text_trunk": {"connection": "{connection_name}"}, + "generate_question": {"connection": "{connection_name}"}, + "validate_question": {"connection": "{connection_name}"}, "generate_suggested_answer": {"connection": "{connection_name}"}, - "validate_suggested_answer": {"connection": "{connection_name}"} + "validate_suggested_answer": {"connection": "{connection_name}"}, } From c5c6b0ede4d1488926e5b16b0752794de9b6705f Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:53:31 +0800 Subject: [PATCH 042/112] Fix some comments (#1912) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- examples/gen_test_data/README.md | 3 + .../{gen_test_data => }/config.ini.example | 0 .../gen_test_data/document-nodes-test.jsonl | 293 ------------------ examples/gen_test_data/gen_test_data/run.py | 26 +- .../gen_test_data/utils/common.py | 21 +- .../gen_test_data/utils/components.py | 17 +- .../{gen_test_data => }/requirements.txt | 0 .../requirements_cloud.txt | 0 8 files changed, 41 insertions(+), 319 deletions(-) create mode 100644 examples/gen_test_data/README.md rename examples/gen_test_data/{gen_test_data => }/config.ini.example (100%) delete mode 100644 examples/gen_test_data/gen_test_data/document-nodes-test.jsonl rename examples/gen_test_data/{gen_test_data => }/requirements.txt (100%) rename examples/gen_test_data/{gen_test_data => }/requirements_cloud.txt (100%) diff --git a/examples/gen_test_data/README.md b/examples/gen_test_data/README.md new file mode 100644 index 00000000000..7bb3e6b1761 --- /dev/null +++ b/examples/gen_test_data/README.md @@ -0,0 +1,3 @@ +# Generate test data + +Please kindly see [this doc](..\docs\how-to-guides\generate-test-data.md) for detailed steps of how to generate test data. \ No newline at end of file diff --git a/examples/gen_test_data/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example similarity index 100% rename from examples/gen_test_data/gen_test_data/config.ini.example rename to examples/gen_test_data/config.ini.example diff --git a/examples/gen_test_data/gen_test_data/document-nodes-test.jsonl b/examples/gen_test_data/gen_test_data/document-nodes-test.jsonl deleted file mode 100644 index 7413d5935d3..00000000000 --- a/examples/gen_test_data/gen_test_data/document-nodes-test.jsonl +++ /dev/null @@ -1,293 +0,0 @@ -{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow.", "document_node": "{\"id_\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b402c5d-538d-408b-9cb1-d66d47fffa40\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a51a60cd4ae560e102258e62ad38f93648f1d46243cb797a66704c23cd9ab80a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"text\": \"Add conditional control to a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\\n\\nThis guide will help you learn how to use activate config to add conditional control to your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`.", "document_node": "{\"id_\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15868ad6-c777-44b2-8e97-9be423ee1483\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ad88a6a9078f088ce0a7ed654c73052d2178573eb746ac2c4162ef58f96634e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f631c8be-64f4-4614-8028-c5f3f603c440\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8af92766f0be0ef9d5426596b0a862f2d8a38e437463aaf6971d06b08c45ce7f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"text\": \"Prerequisites\\n\\nPlease ensure that your promptflow version is greater than `0.1.0b5`.\", \"start_char_idx\": 2, \"end_char_idx\": 86, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::", "document_node": "{\"id_\": \"31293458-8cee-4967-8348-4114666ad247\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"77279509-65c8-4fa1-9ced-eff19c2bd279\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"85d4f1ef1cd02a2a25836c3e629e10e19b777a402ee672b9021ae20a3cd5627d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"84d3241b-3ce6-490b-a1ec-e010be15ab32\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e1e43d9604f949a8a46b0ded3ecc7ab946bf507bb63d660eab69a9fc23482b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"text\": \"Usage\\n\\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\\n\\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\\n\\n::::{tab-set}\\n:::{tab-item} YAML\\n:sync: YAML\\n\\nYou can add activate config in the node section of flow yaml.\\n```yaml\\nactivate:\\n when: ${node.output}\\n is: true\\n```\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\\n!visual_editor\\n\\n- Click on the `Activation config` section in the node you want to add and fill in the values for \\\"when\\\" and \\\"is\\\".\\n!activate_config\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1154, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed", "document_node": "{\"id_\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dd45d45-00c4-4909-a54a-4b03f741623a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b462c2a1e9f20e051210c996e39d721335d61d44c64a788cae8cb40292e9d443\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"31293458-8cee-4967-8348-4114666ad247\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8502f7f6a3a684e08110359962cf933fd6205c6137ca03d3984938dd5f0caa8f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"text\": \"Further details and important notes\\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\\n\\n !provide_default_value\\n\\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\\n\\n !output_bypassed\\n\\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \\\"Bypassed\\\", as shown in the figure below Show. There are three situations in which a node is bypassed.\\n\\n !bypassed_nodes\\n\\n\\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\\n\\n !activate_condition_always_met\\n\\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\\n\\n !activate_when_bypassed\\n\\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\\n\\n !dependencies_bypassed\", \"start_char_idx\": 2, \"end_char_idx\": 1434, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example", "document_node": "{\"id_\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c3e1eb6-23bf-44d1-bda4-5d37c208ee12\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c2d44a764f3b69bd15d3a78bec6b1601edecc6dfbf80ae99d4a6572eec2b15e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26f8eebc-2f4e-463d-909e-3036bacbced4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"104ad7728bdcb7b6bc827031314102e83bb40680a26d4b152df4c3a485533063\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"text\": \"Example flow\\n\\nLet's illustrate how to use activate config with practical examples.\\n\\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\\n- Switch scenario: Explore conditional flow for switch scenarios. View Example\", \"start_char_idx\": 2, \"end_char_idx\": 260, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\n- Run and evaluate a flow", "document_node": "{\"id_\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"782a7b53-7c3c-448c-8908-a78835c5561f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"80d3825fe6697eff08a6a2e7aec7eef79ea6fec62bcbb9e6d0013befe8c13811\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"eeb8393b-c035-447b-bd21-69370f30dc0f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8814786fbc99237cc469055e9dfde76642b1c8c0e3fbe1e51cd12c3f8dcf7781\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"text\": \"Next steps\\n\\n- Run and evaluate a flow\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to construct test data based on documents\nThis guide will help to construct test data based on the provided documents.\nThe test data construction process contains three steps:\n- Split documents to smaller trunks.\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\n- Collect all the test data and remove empty values.", "document_node": "{\"id_\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d762c45d-76f8-44b7-ad01-f762c3b68201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fedab640d7be99800a8d2565a8cb7ec2ab9a551623a2612ab024014c2a0c6269\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1bc13e41-f3f0-4464-876e-ba0533cd06a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/add-conditional-control-to-a-flow.md\", \"file_name\": \"add-conditional-control-to-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 4500, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"63a5a424d036087b40111ee617f1a14bc8b02e9389c2962c565f2243638350e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"text\": \"How to construct test data based on documents\\nThis guide will help to construct test data based on the provided documents.\\nThe test data construction process contains three steps:\\n- Split documents to smaller trunks.\\n- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`.\\nBy `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional.\\n- Collect all the test data and remove empty values.\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data preprocess\nEnter `test_data_gen_local` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c3acac60-fcab-445a-a4e2-189036d3baea\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"875f62cb506a3703f747a728b452b208ee7384cc39c747e00d1a5155dbb0ccbf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"44171902-b256-4f89-bdc2-476e5b64b0cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ad283bfc691f7893296a695e674ee22741ab0d9e8735118fa837b2bc8211d97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"text\": \"Data preprocess\\nEnter `test_data_gen_local` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 145, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get started\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\n> [!Note] This step can be skipped if you just want to have a try.\n\n- Enter test_data_gen_local folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen.py\n ```\n - The generated test data would be a data jsonl file with path you configured in `config.ini`", "document_node": "{\"id_\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dfc13dfd-4b2e-4016-a57a-2d2306d8e5d4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b6ad8f04373fe87782c782471ea659a4fd0e338f74b248a7de9aded5eced04c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ed36e8b-0c39-41da-b1ca-c8d2a8ef2323\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ccbad3322dc5bb9f7074d1a7018bb6ddaec595297562c7ed0e6162b0d1a28f91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"text\": \"Get started\\n- Enter construct_test_data_flow folder to tune your prompt in order to customize your own test data gen logic.\\n> [!Note] This step can be skipped if you just want to have a try.\\n\\n- Enter test_data_gen_local folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen.py\\n ```\\n - The generated test data would be a data jsonl file with path you configured in `config.ini`\", \"start_char_idx\": 2, \"end_char_idx\": 489, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Cloud\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.", "document_node": "{\"id_\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e5582dc9-2527-4689-a66b-3499f60d39ec\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aab6ff042514dbdc1c619bf071e11425c08125c6f6f889eb0c78445e1ddf3b34\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5614ad0a-d6c6-4cd5-a29d-d17dfb7aa6f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edfb5944ae6aa04990f20042e8bf9bd3e7b07577bc0209773c0a49ffc5a4585e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"text\": \"Cloud\\nIf you want to deal with large test data, you can leverage PRS to run flow in pipeline.\", \"start_char_idx\": 2, \"end_char_idx\": 95, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\n```bash\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"880d9550-3b75-4405-b690-dac4ffff2d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ffa284d6ce0438755afec9d24989afc353c5ab2bdee44cfe9dfcfa9287fa312f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"836e7550-0c68-431c-b89c-b9f2d0eea0c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9255f58a90a768fc615c9b4ff5dc0717573ce418d54d619f9c01bc22ff70c745\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"text\": \"Prerequisites\\nEnter `test_data_gen_pipeline` folder, run below command to install required packages.\\n```bash\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 146, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get started\n- Enter test_data_gen_pipeline folder\n - Update configs in `configs.ini`\n - After configuration, run below command to gen test data set.\n ```bash\n python run_test_data_gen_pipeline.py\n ```\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.", "document_node": "{\"id_\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"920d1a8d-54b7-495d-bba0-92c616963af6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff72434cf5652a1df86ae0d8e0a4d1cdb20755160a3b5b04c210cc3d180afe4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f1f078fb-ecc1-44dc-b172-e86bc839727d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9eaec68bc827d9a1b54beec277c4e664c444e02fd67cc3ae009c63734df7b9f2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"text\": \"Get started\\n- Enter test_data_gen_pipeline folder\\n - Update configs in `configs.ini`\\n - After configuration, run below command to gen test data set.\\n ```bash\\n python run_test_data_gen_pipeline.py\\n ```\\n - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash", "document_node": "{\"id_\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"985feda6-5910-4344-8ac2-8e1f004066b7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7566d96cdda7049299b58e66d25859f99137724b7dcaee863800e26459f95290\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"14b0442f-8498-49ea-8426-b0babe8559f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/construct-test-data.md\", \"file_name\": \"construct-test-data.md\", \"file_type\": \"text/markdown\", \"file_size\": 2054, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d699effd3cde67f4ee6cbbf0eedbfffca0f043c7271182b44f2bdc18adc95439\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"text\": \"Deploy a flow using development server\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nWe are going to use the web-classification as\\nan example to show how to deploy a flow.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \\nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \\nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \\nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \\n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \\nvalue as a fallback.\\n\\n\\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1340, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::", "document_node": "{\"id_\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4726d80-ea7e-4fba-9613-db83617bb882\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac3a543e1dceee101173b9bc7ff893ee9fb5a9ceae85efa8194cdc97b790151a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f6bcda8a-3352-4d16-a977-0e86279adf2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"600b799c03bd76ad343ec76052e875a3ac28b8bc1a4e80badf8f166e5e6481e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"text\": \"Serve the flow at localhost:8080\\npf flow serve --source --port 8080 --host localhost\\n```\\n\\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\\n\\n!img\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\nIn visual editor, choose:\\n!img\\nthen choose format:\\n!img\\nthen in yaml editor:\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 364, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::", "document_node": "{\"id_\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5920919b-f0f6-4e82-8f36-b0ed794adca7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3a597bc0d35a21864ac97adf0631fa8b80c3c91c6f9cfdbf2792054289656b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29570953-245b-4a89-8ee5-54a7b64f8348\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9084c7b56e1509251d3576d82cc20ec3a5125a28dfb03ac4cab48380cfaf6a92\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"text\": \"Test endpoint\\n::::{tab-set}\\n:::{tab-item} Bash\\nYou could open another terminal to test the endpoint with the following command:\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\\n:::\\n:::{tab-item} PowerShell\\nYou could open another terminal to test the endpoint with the following command:\\n```powershell\\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -Method POST -ContentType \\\"application/json\\\"\\n```\\n:::\\n:::{tab-item} Test Page\\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 778, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ebc2e916-88ef-49b3-95f7-c181df18e83a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45ffa4d534f92a3990305fa76c49e9bc990763b6a85a443546545b8853581739\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb23b0e9-7041-4c81-9b82-3ad2a814875c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"87532bf6c9be1a822e8cece52c362ae624b90a8dc9b18332cad6cc5747099b6e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using docker.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image.", "document_node": "{\"id_\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"001a5af0-2cb9-4089-997c-197892a18fd7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3cb96282cb3a51734f72174afeb7eb4676623f5801355e4cc3bcf5bf4f520338\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e76c51c-4c85-4d57-8eb7-1c73fa47356b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-dev-server.md\", \"file_name\": \"deploy-using-dev-server.md\", \"file_type\": \"text/markdown\", \"file_size\": 3441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5416bdc2de105c572088fd5dd37e8fa36df37dfb9d76e295f88da09e22f361b5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"text\": \"Deploy a flow using Docker\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are two steps to deploy a flow using docker:\\n1. Build the flow as docker format.\\n2. Build and run the docker image.\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf2f3ae5-ba72-4beb-86a4-1bc49436e1da\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0057da34d9137e38191046124bf42bcf8c1c1f4a027da0f73bac07c083ee4554\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"977f9873-d60a-433c-ad27-037e2e1feb8f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9dfbd5a2305a55a34e9ed453181986ee698a0574409a2af6a42e2f1fbaa6908\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 394, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1ae36579-078a-4568-8aba-c5dda9d14b7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8c279a743b10f1167ab4728059c1d90e3b2b5415f812715b657fd620826065ad\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a3d57faf-7141-47fc-b111-51d16332c298\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e919595ee74289cc9e1a716bafbcb19a5ea2a245d4401e0638b70fede2477507\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.", "document_node": "{\"id_\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4dc49828-c68f-4468-9df7-b79c065f957e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a10de6a73f84be1c1b016021afada237667a01c4928fd4fe49dd16f6339cc2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cd3ec15-84ac-45d2-8572-80ffcc7c56c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"text\": \"Deploy with Docker\\nWe are going to use the web-classification as\\nan example to show how to deploy with docker.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\", \"start_char_idx\": 2, \"end_char_idx\": 244, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cf6e2bc6-78d1-49ec-a697-cb2842d6fe1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ab5f3b806ff2c792734f1c1ad6c7bb6e3568b15939996aaab1650926bd7113b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"942acc00-1c30-45ce-a3d3-ecdea0f2ce11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7db6a771e6d2ab7c4ecb09647a2c5e832805dad68e52066b74e663330fc161cf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"text\": \"Build a flow as docker format app\\n\\nUse the command below to build a flow as docker format app:\\n\\n```bash\\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\\n```\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 283, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```", "document_node": "{\"id_\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"787280bc-ae47-42e9-b7bb-2cf6d722902f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"025c08762a5530fe9b4d08fc2ee90bd910c36f27c24c6b442a3396d375a4c9c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"06af9fa4-38ab-4194-96f8-c23eddfc42be\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3e68b689d1ec816154b72d2864cac274303638fe4c1460d61c223c059fd6c03\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\\n\\nRun the command below to build image:\\n\\n```bash\\ndocker build dist -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container.", "document_node": "{\"id_\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24c4f02a-f692-45ae-b6db-af8952922b50\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305bc2ac535b78373a93bbec09010ac6f2e3a0c5eda71ea5520198308366bd88\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75c12b4c-3d78-4267-b06d-39bd0ae4a432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5424c0206aaa4e8c6e10b3447dd2c3d9ce6e25e7cf63a778733e117ef2e8b45c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"text\": \"Run Docker image\\n\\nRun the docker image will start a service to serve the flow inside the container.\", \"start_char_idx\": 2, \"end_char_idx\": 101, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4d1cbd08-9a15-4dae-9977-1a5b3e0e96e3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"454d361baede9825a6b5a25526bb0659e713e58685077d7448585205f0b99fc2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a15ae87d-c27f-4b52-a046-a18fa3cf5495\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d1c83f478e4c39e087ee742bd5410aaab839e9e606787e4045749c3034398e46\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash", "document_node": "{\"id_\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d4a6eb86-2f08-48ea-a19d-db7442b672a3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2a9c5bb24d9dc83e164398fda42138afca7298371035a2e2e6b5e79b9586e95\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81868d13-5b04-4e06-a66f-97f42b33ef62\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"text\": \"Run with `docker run`\\n\\nYou can run the docker image directly set via below commands:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 94, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```", "document_node": "{\"id_\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4937a2c8-60fb-4b10-ad90-64e2e0ad9203\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5db95208bb6ad14c49e70ef284d9838cf1c03aec34a0529b167858504277263\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"17947c07-fbe3-4fa6-b21b-4ae30ef59d35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0abfb2f804daf44ad7a1e9b31ca54f78ae60fb1d6f3f84aa7ea6a3cb0e4facb8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"text\": \"The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 196, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```", "document_node": "{\"id_\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"094daa74-2704-419b-88a3-d90b6b14be78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d5595bcd64f47bff9d713811f8ea973e1e144428cdeba4c28f2c6e35f373537d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ab95d8fb-8d95-42d5-9f0a-cc0633acafb9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9f23b64bc932bf7d46f8a730797be10c2ab7eee987bb502c43df1e3a99267c6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"text\": \"Test the endpoint\\nAfter start the service, you can use curl to test it:\\n\\n```bash\\ncurl http://localhost:8080/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 249, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes.", "document_node": "{\"id_\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbb19bfc-117b-4108-b0f0-782008d0d6f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d32afb6a7a32f2d7209c5e9c81a494466c7b79c8aec3991f80e2c38b7c7ed429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"708d26ec-4052-4b6c-88ab-b1cc2136d3d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82217d87b37c1a74510aafe5e0a11fef3180038cc95a7a9be1e8e6040d5ca85e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"text\": \"Next steps\\n- Try the example here.\\n- See how to deploy a flow using kubernetes.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment.", "document_node": "{\"id_\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35233e62-7f70-4f02-bcb0-266eb8bab18d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edb6e94975ce9597a7289e364191cb2f0d9ccc41c1dc29ed10078ed5bffe6201\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4540d9a2-738b-41c6-8a5c-30aaad21987b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-docker.md\", \"file_name\": \"deploy-using-docker.md\", \"file_type\": \"text/markdown\", \"file_size\": 3988, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"93966ba9eec3a814d1a4250f132f9e277aac82ed99694b8bf3ea7d642b006fe9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"text\": \"Deploy a flow using Kubernetes\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThere are four steps to deploy a flow using Kubernetes:\\n1. Build the flow as docker format.\\n2. Build the docker image.\\n3. Create Kubernetes deployment yaml.\\n4. Apply the deployment.\", \"start_char_idx\": 2, \"end_char_idx\": 329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash", "document_node": "{\"id_\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"03b68070-8b3a-4e97-b6b5-2efdbd897d0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c32dac478d5c6812b1c1b508fd58be363fd98dc2b93fa1629c5780685a5395ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcf642fc-e20c-4343-aa8c-b153a26aff2d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba995b9baee853a57a99497821a88794bdbbf9a87fb9281940706a61c2cf675d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"text\": \"Build a flow as docker format\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote that all dependent connections must be created before building as docker.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 163, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker.", "document_node": "{\"id_\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9d0ff802-5f7e-4d38-9298-2fe1d72d162a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28da9c8ae14ba1d288700ff08b67f3c64af26e9c9260c5acbe9d3bfce4f0a81c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"34f86dc3-ae05-432a-a254-1cfb4796035e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"95236b36ede2d87f3d66bef62700ba598403524bc1dc9533a4d7fe532c14b423\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as docker format:\\n```bash\\npf flow build --source --output --format docker\\n```\\n:::\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nClick the button below to build a flow as docker format:\\n!img\\n:::\\n::::\\n\\nNote that all dependent connections must be created before exporting as docker.\", \"start_char_idx\": 2, \"end_char_idx\": 490, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files", "document_node": "{\"id_\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a465868-961b-42fa-aff4-023aec92284b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"737ada3363594778b97169c88d91adcd82c3852d6ad94c3afededb851566d7e9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15d7b9c5-8a8c-4927-a06f-175428cb7ba5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"825549759f43741f781ed1a9739c4504fd094f774e462d1c890ee0a788ab106f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"text\": \"Docker format folder structure\\n\\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files\\n - ...\\n- connections: the folder contains yaml files to create all related connections\\n - ...\\n- Dockerfile: the dockerfile to build the image\\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\\n- runit: the folder contains all the runit scripts\\n - ...\\n- settings.json: a json file to store the settings of the docker image\\n- README.md: Simple introduction of the files\", \"start_char_idx\": 2, \"end_char_idx\": 572, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.", "document_node": "{\"id_\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cd6a5ee9-be8a-4cd3-a609-588043b8a5dc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb90193d094243e3f362f8f4834d27aae9ae1cc9c64e9cb898666ef5efcd7a22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe041b12-890e-4475-a844-af22f41c1711\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a2268a9d42a956d466bf22398add292a3fec4902e55e4c93b751f9e5baabce1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"text\": \"Deploy with Kubernetes\\nWe are going to use the web-classification as\\nan example to show how to deploy with Kubernetes.\\n\\nPlease ensure you have create the connection required by flow, if not, you could\\nrefer to Setup connection for web-classification.\\n\\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions.\", \"start_char_idx\": 2, \"end_char_idx\": 494, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```", "document_node": "{\"id_\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca057cce-ae41-4870-86c6-2a7e11df6884\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf0826466e0b7135f7fa8f52748ebd1e0bf36b6c9b70923142f15679305f1509\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2db99430-505b-47e3-8c47-322676269cfa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7edb18377fd24be28937f5a871559270c30dd607e92445cb7cf26616347d2d1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"text\": \"Build Docker image\\n\\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\\n\\nThen run the command below:\\n\\n```bash\\ncd \\ndocker build . -t web-classification-serve\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 266, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```", "document_node": "{\"id_\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"416b4a60-5b95-4610-8818-5c0a950e70b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39fd3d4d93952fc682966479183abf5b004eb51f53bc7a39a608b97d417fa280\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f10a60dd-6841-4e56-9794-a7167a08aa5a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48be0e861dbeb9b77515c24427853e78f032095438b81d02c12a73c696e55776\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"text\": \"Create Kubernetes deployment yaml.\\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\\n\\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\\n```bash\\nencoded_secret=$(echo -n | base64)\\n```\\n\\n```yaml\\n---\\nkind: Namespace\\napiVersion: v1\\nmetadata:\\n name: \\n---\\napiVersion: v1\\nkind: Secret\\nmetadata:\\n name: open-ai-connection-api-key\\n namespace: \\ntype: Opaque\\ndata:\\n open-ai-connection-api-key: \\n---\\napiVersion: v1\\nkind: Service\\nmetadata:\\n name: web-classification-service\\n namespace: \\nspec:\\n type: NodePort\\n ports:\\n - name: http\\n port: 8080\\n targetPort: 8080\\n nodePort: 30123\\n selector:\\n app: web-classification-serve-app\\n---\\napiVersion: apps/v1\\nkind: Deployment\\nmetadata:\\n name: web-classification-serve-app\\n namespace: \\nspec:\\n selector:\\n matchLabels:\\n app: web-classification-serve-app\\n template:\\n metadata:\\n labels:\\n app: web-classification-serve-app\\n spec:\\n containers:\\n - name: web-classification-serve-container\\n image: \\n imagePullPolicy: Never\\n ports:\\n - containerPort: 8080\\n env:\\n - name: OPEN_AI_CONNECTION_API_KEY\\n valueFrom:\\n secretKeyRef:\\n name: open-ai-connection-api-key\\n key: open-ai-connection-api-key\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1691, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.", "document_node": "{\"id_\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2f87d0-7ce6-424f-baf5-9a719bd9e6dd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"477a540f66a6f1ee65bfd60768d2a3d59c1dcadacee96a857fe7f25753276d75\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b5da442b-b082-4ec7-a489-3bc593d9c8bb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d7e8ed5100af34cc984f486cc0252357272204e65f038dae7987ac1ceace2a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"text\": \"Apply the deployment.\\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\\n```bash\\nminikube start\\n```\\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\\n```bash\\nkubectl apply -f deployment.yaml\\n```\\nThis command will create the necessary pods to run your application within the cluster.\\n\\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`.\", \"start_char_idx\": 2, \"end_char_idx\": 697, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```", "document_node": "{\"id_\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e957261-66c9-478e-a059-e80a3e8b0978\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b6370003e6a7da8b9a3332e4ffb0c781dac39e5cfb2e2ceb896790c8a4128be4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8fd4d0b-d217-44a7-9e11-d0fc621ec920\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"564d916a2bdb09104ba370d58ffcfef26d1294fd81995d53e7075f4675179ef8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"text\": \"Retrieve flow service logs of the container\\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\\n\\n```bash\\nkubectl -n logs \\n```\", \"start_char_idx\": 2, \"end_char_idx\": 281, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work.", "document_node": "{\"id_\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fc445c62-3acb-4049-8230-38c9d8466d0b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8215b76f0bcab42a64d833c86863fbdb33dcc95da1fb59674394281d6c6fa40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"109318d3-f363-48b3-98b5-d39c40c01ec2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"975ffe0bbe2e33240a68bcaecb2437374d81ab0e302584e14ec24dfa1b9b0556\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\\nYou'll need to set up the environment variables in the container to make the connections work.\", \"start_char_idx\": 2, \"end_char_idx\": 584, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```", "document_node": "{\"id_\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"272125df-0bcb-4bd6-bf09-c0ec657b16e6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50a786047950de8aa8f76dfa723527bb5c7e34deb5595b227792230410c0f3c1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7e745e2-9b5e-417a-ade8-83fe2766edc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d5acb10b795138b73c65c274d74aefb3c757330751b70e57f03b59a01777de6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"text\": \"Test the endpoint\\n- Option1:\\n\\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\\n To achieve this, execute the following command:\\n\\n ```bash\\n kubectl port-forward : -n \\n ```\\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\\n\\n- Option2:\\n\\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\\n\\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \\n\\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\\n\\n ```bash\\n curl http://localhost:/score --data '{\\\"url\\\":\\\"https://play.google.com/store/apps/details?id=com.twitter.android\\\"}' -X POST -H \\\"Content-Type: application/json\\\"\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1405, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here.", "document_node": "{\"id_\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c90f24c2-70ef-4f4a-bec5-944c963c0017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f33e56b02f183c64dfe8e88bb3d10c17054eb93b672d3dfc9f7b81353b318734\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4970f7c9-d41b-4508-8001-94b1447280a5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c86d60ddb8d7af1c4a3f91b29ba9b787de51c65f8f539d0d944fae4ccfda790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"text\": \"Next steps\\n- Try the example here.\", \"start_char_idx\": 2, \"end_char_idx\": 36, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.", "document_node": "{\"id_\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"78c930c3-0d07-47fa-bcb4-c05ee6801638\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce667521e60986a068e5688e6f7084f84281c241bc239aeacd088d8815f5d142\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d98f55fa-46b5-4aed-b723-25e2fcbfebc3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/deploy-using-kubernetes.md\", \"file_name\": \"deploy-using-kubernetes.md\", \"file_type\": \"text/markdown\", \"file_size\": 8242, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"057fbcfc9b96426d15427377d018346035a85c3b4846fae6bd2439025e4f0596\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"text\": \"Distribute flow as executable app\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nWe are going to use the web-classification as\\nan example to show how to distribute flow as executable app with Pyinstaller.\\n\\n\\nPlease ensure that you have installed all the required dependencies. You can refer to the \\\"Prerequisites\\\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \\n\\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them.\", \"start_char_idx\": 2, \"end_char_idx\": 1262, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash", "document_node": "{\"id_\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"889137df-2303-4e28-9e25-af03a3dade9a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"788efa4a3e263596c0e89a318492f454d61b1947a3249b5817814acecccddf69\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a157c40e-0a53-429b-8b5b-6ea9624f3958\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d8add32dcf1d41a65af0b17846c6711e8090bed987003308ccef346620a128d3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"text\": \"Build a flow as executable format\\nNote that all dependent connections must be created before building as executable.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```", "document_node": "{\"id_\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b8cb107-8895-47b3-bb7b-4afda0994fcf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a5b966cba851cc99e639ac17d4e9ce03f6d8ec9b948b2b2ec507aa7e1a1fa00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"778e673f-76df-47c5-ace0-977b55de96bc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d32de2e0c29d1fbb79b0264833b1d3dc10c17d8c86b80f6ecedb883bf9649dc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"text\": \"create connection if not created before\\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\\n```\\n\\nUse the command below to build a flow as executable format:\\n```bash\\npf flow build --source --output --format executable\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 298, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files.", "document_node": "{\"id_\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cbcb9eaf-2132-477b-8703-ab3179413b0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60e4cbfdadc24044a4f6ff9eff16829666816426530e507bf35ac475af6e80ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8769e0d9-9efd-451f-97b3-ad7080d57b58\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af6a0779c448ac46f4076534c8378abb716348dbd7c47ab3b1d45188a9d475f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"text\": \"Executable format folder structure\\n\\nExported files & its dependencies are located in the same folder. The structure is as below:\\n- flow: the folder contains all the flow files.\\n- connections: the folder contains yaml files to create all related connections.\\n- app.py: the entry file is included as the entry point for the bundled application.\\n- app.spec: the spec file tells PyInstaller how to process your script.\\n- main.py: it will start streamlit service and be called by the entry file.\\n- settings.json: a json file to store the settings of the executable application.\\n- build: a folder contains various log and working files.\\n- dist: a folder contains the executable application.\\n- README.md: Simple introduction of the files.\", \"start_char_idx\": 2, \"end_char_idx\": 733, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```", "document_node": "{\"id_\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8754ca46-b358-442e-85aa-2dd01a1c60b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"525024450d56483fc20362c341d7af6062113e5f8fe6518a8b279a5c130d6ff3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b4c54b08-159f-47c0-9996-8e300f1c6776\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a8af188c9b27c9d5b41728521005dd28ef5ff7469536598ed96831709626bc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"text\": \"A template script of the entry file\\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \\n\\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\\n\\n```python\\nimport os\\nimport sys\\n\\nfrom promptflow._cli._pf._connection import create_connection\\nfrom streamlit.web import cli as st_cli\\nfrom streamlit.runtime import exists\\n\\nfrom main import start\\n\\ndef is_yaml_file(file_path):\\n _, file_extension = os.path.splitext(file_path)\\n return file_extension.lower() in ('.yaml', '.yml')\\n\\ndef create_connections(directory_path) -> None:\\n for root, dirs, files in os.walk(directory_path):\\n for file in files:\\n file_path = os.path.join(root, file)\\n if is_yaml_file(file_path):\\n create_connection(file_path)\\n\\n\\nif __name__ == \\\"__main__\\\":\\n create_connections(os.path.join(os.path.dirname(__file__), \\\"connections\\\"))\\n if exists():\\n start()\\n else:\\n main_script = os.path.join(os.path.dirname(__file__), \\\"main.py\\\")\\n sys.argv = [\\\"streamlit\\\", \\\"run\\\", main_script, \\\"--global.developmentMode=false\\\"]\\n st_cli.main(prog_name=\\\"streamlit\\\")\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1486, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec", "document_node": "{\"id_\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35fb4943-f149-41fa-bdd4-d7e134bf38ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3359e5ab1140c765b2cec249fad745ee49bf26f68fb798200109fd048f8ea886\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79349123-8e17-4f89-af23-5a4226e2c699\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"837ca842ff9989dbfdc3449a42b0dd4356756bf0a7e65a83149bf361be65d326\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"text\": \"A template script of the spec file\\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\\n\\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\\n\\n```spec\", \"start_char_idx\": 2, \"end_char_idx\": 626, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```", "document_node": "{\"id_\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e2b8a188-7744-48aa-bd3e-88622db05d16\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92c55ce053208bb4f5a6a40a6658a2620ec99440bbcb2e2984a892b3ab2b41ec\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a4204fc4-981b-438f-af2f-409e3bcb6c6a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"12e9d2af2ea9175308610b1d324c549653dcb29ef78d440a688d756ae37b2b1e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"text\": \"-*- mode: python ; coding: utf-8 -*-\\nfrom PyInstaller.utils.hooks import collect_data_files\\nfrom PyInstaller.utils.hooks import copy_metadata\\n\\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\\ndatas += collect_data_files('streamlit')\\ndatas += copy_metadata('streamlit')\\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\\ndatas += copy_metadata('keyrings.alt')\\ndatas += collect_data_files('streamlit_quill')\\n\\nblock_cipher = None\\n\\n\\na = Analysis(\\n ['app.py', 'main.py'],\\n pathex=[],\\n binaries=[],\\n datas=datas,\\n hiddenimports=['bs4'],\\n hookspath=[],\\n hooksconfig={},\\n runtime_hooks=[],\\n excludes=[],\\n win_no_prefer_redirects=False,\\n win_private_assemblies=False,\\n cipher=block_cipher,\\n noarchive=False,\\n)\\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\\n\\nexe = EXE(\\n pyz,\\n a.scripts,\\n a.binaries,\\n a.zipfiles,\\n a.datas,\\n [],\\n name='app',\\n debug=False,\\n bootloader_ignore_signals=False,\\n strip=False,\\n upx=True,\\n upx_exclude=[],\\n runtime_tmpdir=None,\\n console=True,\\n disable_windowed_traceback=False,\\n argv_emulation=False,\\n target_arch=None,\\n codesign_identity=None,\\n entitlements_file=None,\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1331, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.", "document_node": "{\"id_\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbbf6b9c-6c93-4225-9464-811c74b323b1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"137b06713f5e2940b2fe428d41780bb47007f0e7ec4af0aae52c6ed2a843f992\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ca689006-3f5e-439a-ba67-2b1c0d7830d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d288e661b6e67ff6e84280315fcd147291f3fb1e4ae8583d6a70d525d0df784a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"text\": \"The bundled application using Pyinstaller\\nOnce you've build a flow as executable format following Build a flow as executable format.\\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```", "document_node": "{\"id_\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0dd26999-3784-4781-b921-16dc8238be64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554ae32ca1c480322848743e9c6da4fd7418108c6046d6cac9f2b84fba6edd71\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"777e9179-5a8a-4270-b9cc-9f7b36f6b802\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b154cd7e38d9ef31db04d65505a2553169dd0c605695ee80cec39b2e2a9ff0ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"text\": \"Connections\\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\ntype: open_ai\\nname: open_ai_connection\\nmodule: promptflow.connections\\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 501, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).", "document_node": "{\"id_\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c2d3b808-b23f-43eb-a47c-1222042cef68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9e38dad6f79b85483297a2e961c7074d5eb7b33e144a833dfeb034ffc8d6380\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0de73fbb-0d38-4ad9-a3bf-2b0762bd1adb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4d850b8b0ee9f9867dd5fb5088d478877871a442ed58b64c88203d4f3149d563\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"text\": \"Test the endpoint\\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \\n\\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\\n\\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\\n\\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux).\", \"start_char_idx\": 2, \"end_char_idx\": 819, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.", "document_node": "{\"id_\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c33c3b24-6d2f-4008-886e-5f909d48d67f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c51e0c6b8fd6ab482b88267abb541c19a26e8a5ace41312d12b6934cfc961ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"94d535d1-c378-4a89-bec4-b63937c3c468\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8a1f6d5cce61785ad7a3208773a30a64c2221d64d03e1210324fee155875f82f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"text\": \"Known issues\\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13.\", \"start_char_idx\": 2, \"end_char_idx\": 162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Try the example here", "document_node": "{\"id_\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a01c5abe-5e5a-4ddb-add2-e3860e52b7cc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e568ec67bd14372ad8610019228abfcab0577cf33fc2d5c498a88ba6889ba595\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b2f19e71-8eaa-454f-91dc-f3c14646f8b4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebba7ed01ffb78bd702cb97058bcea82119d1116bf7526af2d3f7c95e797ddff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"text\": \"Next steps\\n- Try the example here\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fedee87-d831-42e5-8868-b687b8669cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7fee890cde8a5e564cd8a0ac6f8e2e91acb42d8f07a7afb781d3e7fe3abad5de\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"29b4293a-0ec0-444b-8538-5ce10d13079c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/deploy-a-flow/distribute-flow-as-executable-app.md\", \"file_name\": \"distribute-flow-as-executable-app.md\", \"file_type\": \"text/markdown\", \"file_size\": 8604, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e974e3b4ff856d36804224c6b6cfe845e3563d43b002f93e92da0da953d59a6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"text\": \"Develop chat flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 314, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"459ea5a0-07b2-4018-9d73-f5c12560a9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"34672e2e9b5d672a905e718c868c88a5dc1f874f92b883d54f30ea8c8bbc7251\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2571763b-9d03-4be4-b83d-307914ae7b7b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4359c5f31d3a954888b0e6a71134a462baed74ecf23c2bece550d81db5304266\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"text\": \"Flow input data\\n\\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\\n\\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\\n\\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\\n \\n An example of chat history:\\n ```python\\n [\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What types of container software there are?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"There are several types of container software available, including: Docker, Kubernetes\\\"}},\\n {\\\"inputs\\\": {\\\"question\\\": \\\"What's the different between them?\\\"}, \\\"outputs\\\": {\\\"answer\\\": \\\"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\\\"}},\\n ] \\n ```\\n\\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\\n```yaml\\ninputs:\\n chat_history:\\n type: list\\n is_chat_history: true\\n default: []\\n question:\\n type: string\\n is_chat_input: true\\n default: What is ChatGPT?\\n```\\n\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 1811, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools.", "document_node": "{\"id_\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19e1d3da-0011-44c6-842e-f43872513fee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7174bd166b0fb96b0c3c56f110b7bf6b469e98368c15514bfc18c5bda0333ced\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e357e0d4-001f-4489-a00b-182c0197ddda\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac90a676b9b4cfdb9b98a260c9a60d1546fbd6bf6a47a94e871ee4c59b9f014b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\\n\\nFor more information see develop the flow using different tools.\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow.", "document_node": "{\"id_\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec04b974-2730-40eb-b576-9ff5b98ec67a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f683434028ff51d70bcc3e19d09c958ea5fbac263b5b572a16e8cfcc6dfe623\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b0730724-5e37-4af4-988c-eecd1c38acbc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"db26ae81e8538072ce5018e78a64f5f982ec37978fe005a33a2687c53cd83d5e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\\n\\nFor more information see chain your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```", "document_node": "{\"id_\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13f31c7e-48b2-4c8b-a22c-75a2ed4ef4a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09947add90687052194ef8af3b2f29e05eae203b6f2be62d68b64ed4e0c165e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a1370ba2-7b32-4986-b430-d72d2d2f05ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2b8970c840c8c8ac4aa3f405785edc757c8722a6035c45d86c96e8e7f2b3a51\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"text\": \"Set flow output\\n\\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\\n\\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\\n\\n```yaml\\noutputs:\\n answer:\\n type: string\\n reference: ${chat.output}\\n is_chat_output: true\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 453, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.", "document_node": "{\"id_\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8155fe6d-e44d-4b32-a92d-cfd53d2d1dc9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"050307129fb74fe69bb453b44fb4578c009429623df62e027e90bd000d14aea4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9be4eb60-0da4-44b2-a755-2cb97c997524\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-chat-flow.md\", \"file_name\": \"develop-chat-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3623, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0726b7d8fb6ddd02f9664b4a697526b2240cd42e41baf9a429c06c501c759787\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"text\": \"Develop evaluation flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\\n\\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\\n- `Inputs/Outputs definition`\\n- `Nodes`\\n- `Chain nodes in a flow`\\n\\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1329, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.", "document_node": "{\"id_\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9af9790b-674a-4a32-b26d-76d74f80c201\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30a482680af6d77ff4a32b07e7e70496af7d8e659d41e9ddd9bc1a3d2a9e799c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b10da63-99f3-4c3f-ab69-7fd73598a5b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0df7221048d0efe7401946eebde1f4461914e30e90588f641aaf169b7690157a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"text\": \"Evaluation flow example\\n\\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data.\", \"start_char_idx\": 2, \"end_char_idx\": 439, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.", "document_node": "{\"id_\": \"f67eae57-2228-4768-bf9e-752182255315\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a928698-f22c-4012-85c2-e736a3205a32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"806a38502591403dda37598c10e796b0d0b5c7da92670db5caa94bd4059efa78\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"75f14e7e-6f46-4bcf-9f57-98f80e423171\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cbd2fc8ca280a4925e3369542d808347984e7eb17ca31b384ebd2af7b40c05bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"text\": \"Flow inputs\\n\\nThe flow `eval-classification-accuracy` contains two inputs:\\n\\n```yaml\\ninputs:\\n groundtruth:\\n type: string\\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\\n default: APP\\n prediction:\\n type: string\\n description: The actual predicted outputs that your flow produces.\\n default: APP\\n```\\n\\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \\n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\\n\\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 1174, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.", "document_node": "{\"id_\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00b01149-18e5-4fb6-af7c-d1074b90fccb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de34c0d3cae520dc7074bb45e7e48909c31b019d26a7cb740829def7c0c2acdd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f67eae57-2228-4768-bf9e-752182255315\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c558d0f36007a7187eee9c330dd8a51edc96d9d3b9e4a9089862e884736b4862\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"text\": \"Aggregation node\\n\\n\\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\\n\\n```yaml\\n- name: grade\\n type: python\\n source:\\n type: code\\n path: grade.py\\n inputs:\\n groundtruth: ${inputs.groundtruth}\\n prediction: ${inputs.prediction}\\n```\\n\\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\\n\\n```python\\nfrom promptflow import tool\\n\\n@tool\\ndef grade(groundtruth: str, prediction: str):\\n return \\\"Correct\\\" if groundtruth.lower() == prediction.lower() else \\\"Incorrect\\\"\\n```\\n\\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\\n1. It has an attribute `aggregation` set to be `true`.\\n\\n```yaml\\n- name: calculate_accuracy\\n type: python\\n source:\\n type: code\\n path: calculate_accuracy.py\\n inputs:\\n grades: ${grade.output}\\n aggregation: true # Add this attribute to make it an aggregation node\\n```\\n\\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef calculate_accuracy(grades: List[str]):\\n result = []\\n for index in range(len(grades)):\\n grade = grades[index]\\n result.append(grade)\\n\\n # calculate accuracy for each variant\\n accuracy = round((result.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(\\\"accuracy\\\", accuracy)\\n\\n return result\\n```\\n\\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Channel\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\n\\n And we provides a data file like this:\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Channel\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nThen the `grades` value would be `[\\\"Correct\\\", \\\"Correct\\\", \\\"Incorrect\\\"]`, and the final accuracy is `0.67`. \\n\\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs.\", \"start_char_idx\": 2, \"end_char_idx\": 2278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`.", "document_node": "{\"id_\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"952a2672-5398-4540-b942-4d7b4e729b92\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"822605742d13841acd10ffcea5db1d1a13e3e30e09dbb36b3e51a8d80046c79e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b6143c08-66b5-4db2-ba7e-690c0c6dda91\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ebd0be49031397d14d6e348a310b664927aba97730003043116b9374aebbaf0c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"text\": \"More about the list parameter\\n\\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\\n\\n\\n```json\\n{\\\"prediction\\\": \\\"App\\\"}\\n{\\\"prediction\\\": \\\"Academic\\\"}\\n```\\n\\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\\n\\n ```json\\n{\\\"groundtruth\\\": \\\"App\\\"}\\n{\\\"groundtruth\\\": \\\"Wiki\\\"}\\n```\\n\\nIn this case, the `grades` value would be `[\\\"Correct\\\", \\\"Incorrect\\\"]` and the accuracy is `0.5`.\", \"start_char_idx\": 2, \"end_char_idx\": 920, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img", "document_node": "{\"id_\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f7fa17f-8dee-470a-916d-e55d9fe11f1e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60ff341156316a69a77efdcace6fd85fa977b463e106c0110ba68ba78da5f0b5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"254b5c6d-62d9-4e4e-80a3-ec3d7771e75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82b0b60c6bf08a22fee1e07c1ecb3365212eb2b2b9d41e037e7b3dbacd58398f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"text\": \"How to set aggregation node in VS Code Extention\\n\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img", "document_node": "{\"id_\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a7d7d4cd-91ab-4d18-9812-73abab2aaac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62f9779b95c01ecabbbe5cdcda006b117a8dd30ff024f26bd9ec2d33ad4aa7f6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f602cc-f137-4119-891c-334d0cdc48ae\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"10493729bb0e8277f3b7b169651447ecab8ba0643a70a55243c3eb6b750b43d1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"text\": \"How to log metrics\\n:::{admonition} Limitation\\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\\n:::\\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \\n\\n\\n```python\\nfrom typing import List\\nfrom promptflow import log_metric, tool\\n\\n@tool\\ndef example_log_metrics(grades: List[str]):\\n # this node is an aggregation node so it accepts a list of grades\\n metric_key = \\\"accuracy\\\"\\n metric_value = round((grades.count(\\\"Correct\\\") / len(result)), 2)\\n log_metric(metric_key, metric_value)\\n```\\n\\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 777, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema.", "document_node": "{\"id_\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"242a77a2-a306-40bf-93d7-cd6878f5b9bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97d57345e8b5efdb1c430e93e2262ab8995b9b9b3fbf17e9738b3decaf201c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"24235a25-6786-40ba-8923-aa3d9446f837\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-evaluation-flow.md\", \"file_name\": \"develop-evaluation-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 7585, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30cfd54eabe933b7fa75460cb2bdaff062b5eed43f66aab9f14aeb5eec68f518\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"text\": \"Develop standard flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \\nfind additional information about flow yaml schema in Flow YAML Schema.\", \"start_char_idx\": 2, \"end_char_idx\": 322, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types.", "document_node": "{\"id_\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9635de74-544b-4e42-b80e-66f4a9558c00\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668b015e6c989c7d86e3dfcad898c06c44f445fe96bd6d6fccf909a044c1ede0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e2376c5d-b292-47db-983d-4dc66786d392\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf029ac294d20a73a99dee689c4d45a04e036b6f95ec56186ebf2dbc448030ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"text\": \"Flow input data\\nThe flow input data is the data that you want to process in your flow. \\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a flow input in inputs section of flow yaml.\\n```yaml\\ninputs:\\n url:\\n type: string\\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \\nand the input value.\\n\\n!flow_input\\n:::\\n\\n::::\\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\\nFor more input types in a python tool, please refer to Input types.\", \"start_char_idx\": 2, \"end_char_idx\": 757, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.", "document_node": "{\"id_\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"919ca595-35ff-4dba-8a31-26b416b7e3ab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0cf6fa20af96fe27dfaf6ee9484693e4513ea19ec3d3ef8e6b56ebcb0ecaea23\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"96418291-15eb-4b03-a9ef-7c03b21aa113\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1954303b886e615f0add3fbe15f8bf1f2b847cc434a7b4844c5e2c5751ed3baf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"text\": \"Develop the flow using different tools\\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \\nLLM, Python and \\nPrompt and \\nthird-party tool like Serp API, \\nVector Search, etc.\", \"start_char_idx\": 2, \"end_char_idx\": 212, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::", "document_node": "{\"id_\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c60c3d4-098c-4952-ba3b-0de0506f55f4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0bcdc43c78e08ebcf9feadfbe7d897b9998f6b922626ed3c1870d182634403c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fe03f216-2589-43fc-bae2-f0eafae57480\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e287b77c7d9a731766515ffabfc23077d9183a11cfe59cd33a73ccce937e69a4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"text\": \"Add tool as your need\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\\n\\n!add_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 527, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool", "document_node": "{\"id_\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fdf5dd30-8270-4fee-aa1a-abcfbcbb512b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c3fadc7c5b72b98e4ba684a95f971986f4df0034a0a614271c2ffc78074df271\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c147823-ffa5-4649-b848-67e9ed85d518\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"066cf3d71dd15e69e106a3159f92abc079bd01cedc34c65483bf63b5f61d0790\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"text\": \"Edit tool\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\\n\\n```python\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::", "document_node": "{\"id_\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b15324bb-86ed-44cb-bd91-796bc99a3242\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b2175984579bdcc522aadd3d3f03eac2d874f191c3230e9d5f99a7406f02ab54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dc7466f4-11ec-4dd6-8300-4adc748718c0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9e5f73ac40427b473087438cef3de8e1a2271143f743cde2200bbe90b1849923\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"text\": \"The inputs section will change based on the arguments of the tool function, after you save the code\\n@tool\\ndef my_python_tool(input1: str) -> str:\\n return 'hello ' + input1\\n```\\n\\nWe also provide an LLM tool prompt below.\\n\\n```jinja\\nPlease summarize the following text in one paragraph. 100 words.\\nDo not add any information that is not in the text.\\nText: {{text}}\\nSummary:\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \\nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \\ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\\n!edit_tool\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 938, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details.", "document_node": "{\"id_\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8372ff3d-7692-45b9-ac7d-81f0f40101b5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fdbc523c40c6af31143083203d50b7b08d2ea8520099eeda080947118eab3d00\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a2a77582-b46e-4823-801b-92f91afdc886\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be1751114600d59216e4451672b6d2c59b2271216b1abcd809b43f0155f47ae7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"text\": \"Create connection\\nPlease refer to the Create necessary connections for details.\", \"start_char_idx\": 2, \"end_char_idx\": 81, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.", "document_node": "{\"id_\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01934a78-1481-496a-8449-4e8fe6e4a85f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"17c34f9a2db75c40a67d3f3bb44546b8ffe352ba6f837e324a7955cbf41877b2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f429817a-c7ee-43fa-9fb8-b05d3cbcd1f4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"edf0c657d6322a6f902eed5c13225198b90054519ce1872b8adf97642a6a2aae\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"text\": \"Chain your flow - link nodes together\\nBefore linking nodes together, you need to define and expose an interface.\", \"start_char_idx\": 2, \"end_char_idx\": 114, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```", "document_node": "{\"id_\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86c4ea6f-359c-484e-b68e-431c7adcf5c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45184bbd7413f02695ec0459bc753bb0bc538058b5e19dc48636c3bb7e15f50c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a62e9364-25ef-4e82-a87e-7e926a9f6e74\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5f26881e426ac6bb231d987cee3b7662ee6b6cf8f0f828875589437e1293e587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"text\": \"Define LLM node interface\\nLLM node has only one output, the completion given by LLM provider.\\n\\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \\nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \\ntemplating language. For example:\\n\\n```jinja\\nYour task is to classify a given url into one of the following types:\\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\\nThe classification will be based on the url, the webpage text content summary, or both.\\n\\nHere are a few examples:\\n{% for ex in examples %}\\nURL: {{ex.url}}\\nText content: {{ex.text_content}}\\nOUTPUT:\\n{\\\"category\\\": \\\"{{ex.category}}\\\", \\\"evidence\\\": \\\"{{ex.evidence}}\\\"}\\n\\n{% endfor %}\\n\\nFor a given URL : {{url}}, and text content: {{text_content}}.\\nClassify above url to complete the category and indicate evidence.\\nOUTPUT:\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 958, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```", "document_node": "{\"id_\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0d6a1e23-9c61-456e-b5f8-6646774e7517\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7098a85fc27d133c1dd382abf3c7c82f3704b115745129d0b4c63e59891bbcb6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"da299183-7bae-4eeb-96fe-0a91cfe582dc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed788183c757ff39ebc47584d3979a6f33dec27f0dfca9dac72b008b283dd9e1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"text\": \"Define Python node interface\\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \\nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\\nFor example:\\n\\n```python\\nimport json\\nfrom promptflow import tool\\n\\n@tool\\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\\n try:\\n print(input_str2)\\n return json.loads(input_str)\\n except Exception as e:\\n print(\\\"input is not valid, error: {}\\\".format(e))\\n return {\\\"category\\\": \\\"None\\\", \\\"evidence\\\": \\\"None\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 595, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together.", "document_node": "{\"id_\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2b337a61-282c-4aa0-8cc2-a303344a3a87\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"72154d54360f4b5a82884b63734ac5365a69ed681123ba1e32eb8718628ee58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"61b1bfce-d45a-47c2-a76a-e0a3896212e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efbedb5c149d1913881e05fc2ab1569c4c862610e2aa3d8d22d4ae9ac01aa62b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"text\": \"Link nodes together\\nAfter the interface is defined, you can use:\\n\\n- ${inputs.key} to link with flow input.\\n- ${upstream_node_name.output} to link with single-output upstream node.\\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\\n\\nBelow are common scenarios for linking nodes together.\", \"start_char_idx\": 2, \"end_char_idx\": 313, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.", "document_node": "{\"id_\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c06825b-2eca-437e-81ef-b400683e5107\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dc503dd0dd29d203ef8868753fef7c97754d409dead2aab234f87acf6388f82b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f12bbf85-3d7c-46bc-b5c1-d72116266d4e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"668f3ee219f866df62ba34c6b51c071f58313b8e44d5d5f102d6ffefe12a1aa6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"text\": \"Scenario 1 - Link LLM node with flow input and single-output upstream node\\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \\nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link the LLM node input with flow input by `${inputs.url}`. \\nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \\nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n url: ${inputs.url} # Link with flow input\\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \\nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \\n\\n!link_llm_with_flow_input_single_output_node\\n:::\\n\\n::::\\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \\n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1746, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.", "document_node": "{\"id_\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57a1605b-80c4-4052-8504-33374b92caee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8cf98f614b216b0d506c5cbbb9581ef3ca68bad51e3877c4935b7ef16ecb6e4c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c085205e-acfb-4296-96b3-4f0c7a07489e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbd6ed5cbccbb3ba6a2c51e324e001bc06d90f2acea58114df96122f04dc1f5f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"text\": \"Scenario 2 - Link LLM node with multi-output upstream node\\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \\n```yaml\\n- name: classify_with_llm\\n type: llm\\n source:\\n type: code\\n path: classify_with_llm.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n suffix: \\\"\\\"\\n max_tokens: 128\\n temperature: 0.2\\n top_p: 1\\n echo: false\\n presence_penalty: 0\\n frequency_penalty: 0\\n best_of: 1\\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \\nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\\n\\n!link_llm_with_multi_output_node\\n:::\\n::::\\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1273, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.", "document_node": "{\"id_\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8126884c-df49-43ba-9d3f-1a9638cd235d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a42c7be5b7c364c1f60b09c4d2756084cd1c9d628ef3fad2380f9b736ce02b20\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac8004c4-138a-4af7-8aa4-109fd595954b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b923cb984a84d786644664c033721e24eb75dcc79d491b25caa588acab7cf886\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"text\": \"Scenario 3 - Link Python node with upstream node/flow input\\nAfter you add a new Python node and edit the code file like Define Python node interface], \\ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \\nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n```yaml\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs:\\n input_str: ${inputs.url} # Link Python node with flow input\\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n!link_python_with_flow_node_input\\n:::\\n\\n::::\\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \\ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly.\", \"start_char_idx\": 2, \"end_char_idx\": 1045, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::", "document_node": "{\"id_\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c8228df-9c72-4af5-b9c4-7369ed0f78e8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"35e2f7644a2153debed83c13170ff3cc72a2a0396587f4c47bebb3e814c9c005\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"658ec4e9-9423-418f-934b-2cd5e133b5cd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f91b1717e03d4e2f06e5fc53460816f3407337aabb6e92eda3162a1bfd9165ea\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"text\": \"Set flow output\\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \\nmultiple nodes in one place. Moreover, flow output helps:\\n\\n- Check bulk test results in one single table.\\n- Define evaluation interface mapping.\\n- Set deployment response schema.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \\nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \\n`convert_to_dict`.\\n\\n```yaml\\noutputs:\\n category:\\n type: string\\n reference: ${convert_to_dict.output.category}\\n evidence:\\n type: string\\n reference: ${convert_to_dict.output.evidence}\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \\nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \\n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\\n\\n!flow_output\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 1194, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.", "document_node": "{\"id_\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"66907d7f-5f3f-48c2-9669-2c366a8ae143\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"75e4c5eee350016added3ec9fe497df916fbd71d627b305a3190eb538cc362a4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62eb47b3-4795-4bc9-af78-a499edf46c8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/develop-standard-flow.md\", \"file_name\": \"develop-standard-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 11852, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58533027696c3e84c30d470b38c56731036327323a6397da8103462459dde00\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"text\": \"Referencing external files/folders in a flow\\n\\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\\n\\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/classify_with_llm.jinja2\\n- ../web-classification/convert_to_dict.py\\n- ../web-classification/fetch_text_content_from_url.py\\n- ../web-classification/prepare_examples.py\\n- ../web-classification/summarize_text_content.jinja2\\n- ../web-classification/summarize_text_content__variant_1.jinja2\\n```\\n\\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\\n\\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\\n\\n```yaml\\nnodes:\\n- name: fetch_text_content_from_url\\n type: python\\n source:\\n type: code\\n path: fetch_text_content_from_url.py\\n inputs:\\n url: ${inputs.url}\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n```\\n\\nThe entry file \\\"fetch_text_content_from_url.py\\\" of the tool node \\\"fetch_text_content_from_url\\\" is located in \\\"../web-classification/fetch_text_content_from_url.py\\\", as specified in the additional_includes field. The same applies to the \\\"summarize_text_content\\\" tool nodes.\\n\\n> **Note**:\\n>\\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\\nTake the following YAML structure as an example:\\n\\n```yaml\\nadditional_includes:\\n- ../web-classification/prepare_examples.py\\n- ../tmp/prepare_examples.py\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n- name: prepare_examples\\n type: python\\n source:\\n type: code\\n path: prepare_examples.py\\n inputs: {}\\n``` \\n\\nIn this case, the system will use \\\"../tmp/prepare_examples.py\\\" as the entry file for the tool node \\\"prepare_examples\\\". Even if there is a file named \\\"prepare_examples.py\\\" in the flow folder, the system will still use the file \\\"../tmp/prepare_examples.py\\\" specified in the `additional_includes` field.\\n\\n> Tips:\\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud.\", \"start_char_idx\": 2, \"end_char_idx\": 3451, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.", "document_node": "{\"id_\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ee2b7611-b6e8-41d5-bcb7-857e344fb92a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"14430280f768c113dbf9e583b57be7eb327a7edbaf80889e72c017b668b89311\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f7188882-0ba1-4e95-93a7-96384a170ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-flow/referencing-external-files-or-folders-in-a-flow.md\", \"file_name\": \"referencing-external-files-or-folders-in-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3714, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5e135dfebda3072615c51d3cdfba5e029eead0f66affb411c69a5e8939ac367\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"text\": \"Adding a tool icon\\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\\n\\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon.\", \"start_char_idx\": 2, \"end_char_idx\": 295, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference.", "document_node": "{\"id_\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"57058ab8-fa89-4e8a-a86f-8f8f6d8843bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb4c72a52e728f4c06cb906c2535c4d2d1e3e2b9c9ccf274d6c6fa6a2257c4c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e8dff188-bfaf-4306-9eb0-a5d2796c7b53\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25e034c0ebe461b5034c4cd175a3fa374233006154db66816d63bc73416961f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"text\": \"Prerequisites\\n\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\\n- Create a tool package as described in Create and Use Tool Package.\\n- Prepare custom icon image that meets these requirements:\\n\\n - Use PNG, JPG or BMP format.\\n - 16x16 pixels to prevent distortion when resizing.\\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \\n\\n See this example as a reference.\", \"start_char_idx\": 2, \"end_char_idx\": 526, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Add tool icon with _icon_ parameter", "document_node": "{\"id_\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5b08ae97-5546-4d8a-8170-1e00ceabc742\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"200723951d139ca9f747a814fe55f43bf4c437d9ca9165060bd9ec9962224d93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1177f09-640a-48a1-8bb5-e0024714b090\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f81eec2afe7a18e45a54571c934aadc60081b1660cc9b0a8ba295c4629f3a2f0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"text\": \"Add tool icon with _icon_ parameter\", \"start_char_idx\": 2, \"end_char_idx\": 37, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```", "document_node": "{\"id_\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"04cb4765-6550-47b7-9cee-1ae8b0d9dfef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bfa267daed05b823404227af4ca8eaabad2e04b3069149430390fe220d5df245\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"278f6ac1-e68c-46ca-bef2-15f599cb371f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2e7ccdccd321c77a2c753ccd738676260154a1a859561ec3b06fe249e49693ad\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"text\": \"Initialize a package tool with icon\\nYou can use pf tool init to initialize a package tool with icon:\\n```bash\\npf tool init --package --tool --set icon=\\n```\\n\\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\\n```python\\nfrom pathlib import Path\\n\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n icon=Path(__file__).parent.parent / \\\"icons\\\" / \\\"custom-tool-icon.png\\\"\\n)\\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\\n\\nThe folder structure of the generated tool package is as follows:\\n```\\n\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u251c\\u2500\\u2500\\u2500icons\\n\\u2502 \\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500\\n .py\\n utils.py\\n __init__.py\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1222, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension", "document_node": "{\"id_\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a6b4670f-1911-41c2-816e-2afb835bce01\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1abe48bedddbcc1787d670a0952e7a3a82f2de7afce76d2d985ec9d05645a0cd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc78d8-8cc1-4a36-b627-678cbfc5fda6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ff76bd43d0d74fc6bd49e83a2648a83bfa14745be6f00cf39414dfd276af821\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"text\": \"Verify the tool icon in VS Code extension\\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \\n!custom-tool-with-icon-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 176, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```", "document_node": "{\"id_\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9538f81c-1db6-4c2a-bbb5-ef36ca94fe44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbae9925b9e8426daba0ea2c01d494ed28a0e6dfd7437106812478371a299361\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ad897b3-b5ab-4801-9261-0d4c72d56ce6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"addc2536bbff9cdb9231c65312f4627a338759120fbcc9437c660e6aac1dff58\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"text\": \"FAQ\\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\\n```\\npython \\\\tool\\\\convert_image_to_data_url.py --image-path -o \\n```\\nFor example:\\n```\\npython D:\\\\proj\\\\github\\\\promptflow\\\\scripts\\\\tool\\\\convert_image_to_data_url.py --image-path D:\\\\proj\\\\github\\\\promptflow\\\\examples\\\\tools\\\\tool-package-quickstart\\\\my_tool_package\\\\icons\\\\custom-tool-icon.png -o output.html\\n```\\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\\n```html\\n\\n\\n\\n\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 580, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```", "document_node": "{\"id_\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"699ce5b2-187c-46f3-9f9c-b3b535acd91c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d707888b7220646c246f2b7886f82a2e315b193744d4f9c407ffd60a44e1c6a3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7dc8ff69-19f1-4f26-9f18-0403323491c6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"18b3b85b7cf22522794415e0e38a877eb11d7edc102db358e6bbf61c64b98eba\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"text\": \"Can I add a tool icon to an existing tool package\\n\\nYou can follow these steps to add an icon to an existing package tool:\\n1. Copy the icon image to the package folder.\\n2. Configure the icon for the tool.\\n\\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\\n ```python\\n from promptflow import tool\\n\\n @tool(name=\\\"tool_name\\\", icon=)\\n def tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n ```\\n3. Update `MANIFEST.in` in the package folder.\\n\\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\\n ```\\n include \\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 769, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.", "document_node": "{\"id_\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ca4ccdf3-090d-45f9-9d6a-07979afc72ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3d4af681b648feaf107b311553825afe2354879d3aec8e50615a0ed039d2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"656a3b31-1ea4-4106-a197-bf366cb80c11\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f8988a1028e268288b518b9adc9f6c346c4505ff16a7e681caf9004ea2b87550\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"text\": \"Can I add tool icons for dark and light mode separately?\\nYes, you can add the tool icon data to the tool code as follows:\\n```python\\nfrom promptflow import tool\\n\\n@tool(name=\\\"tool_name\\\", icon_dark=, icon_light=)\\ndef tool_func(input_text: str) -> str:\\n # Tool logic\\n pass\\n```\\n\\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\\n```python\\npf tool init --tool --set icon_dark= icon_light=\\n```\\n\\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode.\", \"start_char_idx\": 2, \"end_char_idx\": 756, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field.", "document_node": "{\"id_\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"01518a9e-e18d-4949-9626-094903eea51c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"be5cd30b0f09f966dbb2e5f5edbbbd36d25301c73f444f5f31f9585dba4c0c81\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dcc0b6e9-b62e-4cf6-a993-86bec0aadedd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-a-tool-icon.md\", \"file_name\": \"add-a-tool-icon.md\", \"file_type\": \"text/markdown\", \"file_size\": 6380, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58a831b152251b533761ae4f43d6c520f7402d2da6f4ad673f3028c2e96fbc25\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"text\": \"Adding category and tags for tool\\n\\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\\n\\n| Attribute | Type | Required | Description |\\n| --------- | ---- | -------- | ----------- |\\n| category | str | No | Organizes tools into folders by common features. |\\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\\n\\n**Important Notes:**\\n- Tools without an assigned category will be listed in the root folder.\\n- Tools lacking tags will display an empty tags field.\", \"start_char_idx\": 2, \"end_char_idx\": 1063, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.", "document_node": "{\"id_\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8779355d-d614-4b16-835d-d0721a33dc45\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74313f42ccdbca8b27db5e01299294ae7b0bf1a6ec47b19245225df77fa5f403\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bc18e3c9-ddd1-4669-bd6f-d5c6229ae9ce\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd6819b1e05fd07676568b98b526629641f359c55315dbf4d3cdff7f786f3d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 186, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```", "document_node": "{\"id_\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8d6db4b6-5a82-49d7-ac61-f26dfe211484\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8444fd90e8cf147e712f4a38ad588c732d2520d4f678a8b1455c1853ec50da8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8c512284-07f5-4d10-b3fc-8656c398906b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6b6a6649f9307080598a0378f596ea989676266ad0f2718d7e102b6f73d9fbee\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"text\": \"How to add category and tags for a tool\\n\\nYou can use pf tool init to initialize a package tool with category and tags:\\n```python\\npf tool init --package --tool --set category= tags=\\n\\n```\\n\\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\\n```python\\npf tool init --tool my_tool --set name=\\\"My First Tool\\\" description=\\\"This is my first tool\\\" category=\\\"test_tool\\\" tags=\\\"{'tag1':'value1','tag2':'value2'}\\\"\\n```\\nThe generated tool script is as follows, where category and tags have been configured on the tool:\\n```python\\nfrom promptflow import tool\\nfrom promptflow.connections import CustomConnection\\n\\n\\n@tool(\\n name=\\\"My First Tool\\\",\\n description=\\\"This is my first tool\\\",\\n category=\\\"test_tool\\\",\\n tags={\\\"tag1\\\": \\\"value1\\\", \\\"tag2\\\": \\\"value2\\\"},\\n)\\ndef my_tool(self, input_text: str) -> str:\\n # Replace with your tool code.\\n # Usually connection contains configs to connect to an API.\\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\\n # Not all tools need a connection. You can remove it if you don't need it.\\n return \\\"Hello \\\" + input_text\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1189, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag", "document_node": "{\"id_\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddf33403-cee1-4e76-a2ab-f6ec20ab5391\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce8dfca466c3c5f8a3b0f25cefa6575a14aac45fc4c6bd71b81025b60a999429\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7d90f02-ef9d-45c1-9b3c-cfb2efc22390\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8baa6744c16e159750eaea31c2a68e0c3074db65452450b412f0e7eed0349fd3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"text\": \"Tool with category and tags experience in VS Code extension\\nFollow the steps to use your tool via the VS Code extension.\\n- Experience in the tool tree\\n!category_and_tags_in_tool_tree\\n\\n- Experience in the tool list\\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\\n!category_and_tags_in_tool_list\\nFurthermore, you have the option to search or filter tools based on tags:\\n!filter_tools_by_tag\", \"start_char_idx\": 2, \"end_char_idx\": 443, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```", "document_node": "{\"id_\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"344346f5-1b0d-44f2-9731-80d27521e130\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4efeae08cd9f495b68b9d5c9738dbcf9caa03eae09cf94a5fc1567bd33f706d5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae6963a1-07db-4eb3-8e5d-aab2e6b511a1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4be33c97f9e79c0726e6d65cc51bf80966601830420835a24abcc906b28ee2a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"text\": \"FAQ\\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\\n```python\\n@tool(\\n name=\\\"tool_name\\\",\\n description=\\\"This is tool_name tool\\\",\\n category=,\\n tags=,\\n)\\ndef tool_name(input_text: str) -> str:\\n # tool logic\\n pass\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 285, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list", "document_node": "{\"id_\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8eb7c175-5eb4-4be1-904f-f815a877641c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"761b3c022375969240ebb1501804424057266c488c43981e362d1b0a23a21831\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"724b6d21-31bd-4165-ac4e-175ba20a0055\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/add-category-and-tags-for-tool.md\", \"file_name\": \"add-category-and-tags-for-tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 3838, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"255032e10b837ed444350396a62725ae9d56f6cf3cf01c92c24707c4a1433be0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"text\": \"Create and use tool package\\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\\n\\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\\n\\nAfter successful installation of the package, your custom \\\"tool\\\" will show up in VSCode extension as below: \\n!custom-tool-list\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.", "document_node": "{\"id_\": \"936062d7-da6f-425e-8071-eec693938da0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4e9a3b-17ed-41b4-af95-541b9285769d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6d0592c1fbf449100098a1897232c851f0023246794d1404df65486e26b30ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c171b753-edaf-46fd-bafb-77b414335eba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"001cab77051d0ddc69b45f04b7b22ef61c77d62ef5ae176efbf1ae3b6b054820\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"text\": \"Create your own tool package\\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section.\", \"start_char_idx\": 2, \"end_char_idx\": 150, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```", "document_node": "{\"id_\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02d44090-c629-4857-8fb8-f857f9743f31\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c283b0aa603e66d9c0593d1f97704896afe43f3c0562e30fdd8b1490164d4b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"936062d7-da6f-425e-8071-eec693938da0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"39e3cbabceff838a891d658f0bb3bcbb0870f85cba8f3eca303c24ce954fc4f8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"text\": \"Prerequisites\\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\\n```\\npip install promptflow\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 157, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure.", "document_node": "{\"id_\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cb076bf-bda4-491f-b36b-90646bf39825\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4d88291fa44db81f7df84aa930a343b8e56aa76fbd22cd6831525a828d2bdb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f418a96e-5b91-40a7-9ce4-19e42506f8e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4e3bb5e4a34a364f37e2cb400e307357aa28e3aedcdc9c86ad2e6d015fcbcd2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"text\": \"Create custom tool package\\nYou can use pf tool init to initialize a package tool in current folder:\\n\\n```bash\\npf tool init --package --tool \\n\\n```\\nFor example:\\n```bash\\npf tool init --package hello_world --tool hello_world_tool\\n```\\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\\n\\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\\n\\n```\\nhello_world/\\n\\u2502 MANIFEST.in\\n\\u2502 README.md\\n\\u2502 setup.py\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500hello_world/\\n hello_world_tool.py\\n utils.py\\n __init__.py\\n```\\n\\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\\n\\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \\n\\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\\n ```python\\n entry_points={\\n \\\"package_tools\\\": [\\\" = :\\\"],\\n },\\n ```\\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\", \"start_char_idx\": 2, \"end_char_idx\": 3024, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.", "document_node": "{\"id_\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb45998c-8b7b-47c6-8563-3cc43e460689\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e56c43e15838921293454392a9f5431b91b0d337bc691b653cef4250b6d5e52b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4c721a-ecd4-41d3-b7a8-10bd964ff3d0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0ac26fdf536be34672dfec48b3a79e336fe44048498adc37b72b3c53c537366\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"text\": \"Build and share the tool package\\n Execute the following command in the tool package root directory to build your tool package:\\n ```\\n python setup.py sdist bdist_wheel\\n ```\\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\\n\\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\\n\\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\\n\\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`.\", \"start_char_idx\": 2, \"end_char_idx\": 1081, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension", "document_node": "{\"id_\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a2aac4b6-dee0-40c8-b78f-fa6c85823c0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6dac8b1537a6e23487b63d97bffeeda30df26f43280d740357e8e84c36c3081a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c6562b05-ccc4-40c1-8c9f-ca0c5cc98d1f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"294d30aacba7b7ded67862b19a5523723db2ec374dd5675759bf00e7aa9c825d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"text\": \"Use your tool from VSCode Extension\\n* Step1: Install Prompt flow for VS Code extension. \\n\\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\\n ```\\n (local_test) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> conda activate prompt-flow\\n (prompt-flow) PS D:\\\\projects\\\\promptflow\\\\tool-package-quickstart> pip install .\\\\dist\\\\my_tools_package-0.0.1-py3-none-any.whl\\n ``` \\n\\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\\n!auto-list-tool-in-extension\", \"start_char_idx\": 2, \"end_char_idx\": 745, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.", "document_node": "{\"id_\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25ceaf4b-d75c-452e-b038-cb1cff034017\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a67937099d4ff70a170e33ffc30f7d928d2833bfa58a1bbe333e21e7507e09e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c60e1590-caf0-493d-acad-b3aa902aa075\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01e74fd73c2f20bb5078de77a6448f00f3e575f8d1731cc42df3fae7c18aa2db\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"text\": \"FAQs\\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\\n\\n 1. Make sure to install the tool package in your conda environment before executing this script.\\n 2. Create a python file anywhere and copy the content below into it.\\n ```python\\n import importlib\\n import importlib.metadata\\n\\n def test():\\n \\\"\\\"\\\"List all package tools information using the `package-tools` entry point.\\n\\n This function iterates through all entry points registered under the group \\\"package_tools.\\\"\\n For each tool, it imports the associated module to ensure its validity and then prints\\n information about the tool.\\n\\n Note:\\n - Make sure your package is correctly packed to appear in the list.\\n - The module is imported to validate its presence and correctness.\\n\\n Example of tool information printed:\\n ----identifier\\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\\n \\\"\\\"\\\"\\n entry_points = importlib.metadata.entry_points()\\n PACKAGE_TOOLS_ENTRY = \\\"package_tools\\\"\\n if isinstance(entry_points, list):\\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\\n else:\\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\\n for entry_point in entry_points:\\n list_tool_func = entry_point.load()\\n package_tools = list_tool_func()\\n\\n for identifier, tool in package_tools.items():\\n importlib.import_module(tool[\\\"module\\\"]) # Import the module to ensure its validity\\n print(f\\\"----{identifier}\\\\n{tool}\\\")\\n\\n if __name__ == \\\"__main__\\\":\\n test()\\n ```\\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed.\", \"start_char_idx\": 2, \"end_char_idx\": 2062, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.", "document_node": "{\"id_\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"361d2447-b4f8-4f35-a1af-8892d249e13a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"55e3663e73f77321999c9beef546505b42179a322bae4b28bb738f35af78f7c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea4591cd-bc51-4231-96ca-fdafc77a4c79\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1629cb031042c7223887895c68dce93c8ddca2237db5d96604c3e854c54dfae0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"text\": \"Why am I unable to upload package to PyPI?\\n* Make sure that the entered username and password of your PyPI account are accurate.\\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one.\", \"start_char_idx\": 2, \"end_char_idx\": 654, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs", "document_node": "{\"id_\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da4c66da-b14f-452c-9927-49b39d9cd181\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8d7ea9fb7c1ff5d72950bbb6b92aa6aafe99722a29b7723c16ec2fae992a4d83\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6611f602-5f96-4ce0-bb79-839cf29a9d1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a7ce62b7135db363381fafd2b66abe9ebf12292beec69c62351e88c17b2c1e2c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"text\": \"Advanced features\\n- Add a Tool Icon \\n- Add Category and Tags for Tool \\n- Create and Use Your Own Custom Strong Type Connection \\n- Customize an LLM Tool \\n- Use File Path as Tool Input \\n- Create a Dynamic List Tool Input \\n- Create Cascading Tool Inputs\", \"start_char_idx\": 2, \"end_char_idx\": 258, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.", "document_node": "{\"id_\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f82dbbc6-86b4-4928-8eec-c50b955110f6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbfca4e40603faa2d69519faaf0e6a2bee1c43b0f5f9d625ef9172cf40e2d822\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"510dc328-baa0-4e5d-a974-f15868fd7f86\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-and-use-tool-package.md\", \"file_name\": \"create-and-use-tool-package.md\", \"file_type\": \"text/markdown\", \"file_size\": 9747, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a3b35c1f12b80e72449b739b01b4938cacfa560fe93d9238cb43db017317c3c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"text\": \"Creating cascading tool inputs\\n\\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools.\", \"start_char_idx\": 2, \"end_char_idx\": 303, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6da446b1-c160-474d-89f3-f9f3659daaa0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f552409c79c5e4003de24d7f1a2f627a4005d8711975f42568830bb585d7fc54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"72dd39e5-4575-4ebb-aa5f-0d0d6c5fb0d7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2fc2fed448b4640fc907d181706131b4687b11e3c3d511abdac2ce8a0d828a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"text\": \"Prerequisites\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 237, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```", "document_node": "{\"id_\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5fbd0902-ccbb-4e1e-b205-f191c87d3f39\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fae50d17a2ec06631c825bbd2772d5c2952857c4632a2670168971f1401afe09\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7ef71cad-80aa-4c19-911d-7a3439bf4a4f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ea58736f03c8763b6f89ecebf49916d420b999860bead53ccdf35c973cf1f047\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"text\": \"Create a tool with cascading inputs\\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\\n\\nDevelop the tool function, following the cascading inputs example. Key points:\\n * Use the `@tool` decorator to mark the function as a tool.\\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\\n * Conditionally use inputs in the tool logic based on `user_type`.\\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\\n\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass UserType(str, Enum):\\n STUDENT = \\\"student\\\"\\n TEACHER = \\\"teacher\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Enabled By Value\\\",\\n description=\\\"This is my tool with enabled by value\\\",\\n input_settings={\\n \\\"teacher_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.TEACHER]),\\n \\\"student_id\\\": InputSetting(enabled_by=\\\"user_type\\\", enabled_by_value=[UserType.STUDENT]),\\n }\\n)\\ndef my_tool(user_type: UserType, student_id: str = \\\"\\\", teacher_id: str = \\\"\\\") -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\n :param user_type: user type, student or teacher.\\n :param student_id: student id.\\n :param teacher_id: teacher id.\\n :return: id of the user.\\n If user_type is student, return student_id.\\n If user_type is teacher, return teacher_id.\\n \\\"\\\"\\\"\\n if user_type == UserType.STUDENT:\\n return student_id\\n elif user_type == UserType.TEACHER:\\n return teacher_id\\n else:\\n raise Exception(\\\"Invalid user.\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png", "document_node": "{\"id_\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95ee1c93-3fd8-4ccf-8c4c-76c63f5e6d68\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"04fcb935e815a4801293eb7a2cf3895cc849cac7965b173b1c94fff6e473857e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"aee4c691-bf52-408f-bb9a-28ece39491b2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f720c8819995eb550a8f0216a2f62674848ae7c6a9a27a05b67f3a896a01885\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"text\": \"Use the tool in VS Code\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\\n\\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\\n!before_user_type_selected.png\\n!after_user_type_selected_with_student.png\\n!after_user_type_selected_with_teacher.png\", \"start_char_idx\": 2, \"end_char_idx\": 417, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections.", "document_node": "{\"id_\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d27b2b3a-1f85-4708-b438-61936edefd56\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4cc9eeedc959aaa970d6346b761f25e5ade25ff26ab512556114ab76bebacf51\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2302ff7-4608-4b03-bbb0-99e39daadf03\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3ba1298f02416b986ccf7505d31ecf74b0b4302cc5c2c74964afb7eddce814af\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"text\": \"FAQs\\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\\n```python\\nfrom enum import Enum\\n\\nfrom promptflow.entities import InputSetting\\nfrom promptflow import tool\\n\\n\\nclass EventType(str, Enum):\\n CORPORATE = \\\"corporate\\\"\\n PRIVATE = \\\"private\\\"\\n\\n\\nclass CorporateTheme(str, Enum):\\n SEMINAR = \\\"seminar\\\"\\n TEAM_BUILDING = \\\"team_building\\\"\\n\\n\\n@tool(\\n name=\\\"My Tool with Multi-Layer Cascading Inputs\\\",\\n description=\\\"This is my tool with multi-layer cascading inputs\\\",\\n input_settings={\\n \\\"corporate_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[EventType.CORPORATE]),\\n \\\"seminar_location\\\": InputSetting(enabled_by=\\\"corporate_theme\\\", enabled_by_value=[CorporateTheme.SEMINAR]),\\n \\\"private_theme\\\": InputSetting(enabled_by=\\\"event_type\\\", enabled_by_value=[CorporateTheme.PRIVATE]),\\n }\\n)\\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\\n \\\"\\\"\\\"This is a dummy function to support enabled by feature.\\\"\\\"\\\"\\n pass\\n```\\nInputs will be enabled in a cascading way based on selections.\", \"start_char_idx\": 2, \"end_char_idx\": 1231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.", "document_node": "{\"id_\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67f40a0f-b078-4cc6-ab1e-949e061951a4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"253f1ef689b236779c4139c7b8a8596611a636413e760e9e65f92f24ba76df17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"926d8370-2b29-45fd-bcad-4fd07269d020\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-cascading-tool-inputs.md\", \"file_name\": \"create-cascading-tool-inputs.md\", \"file_type\": \"text/markdown\", \"file_size\": 5122, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5b7d39124956c95630f33411027bf03104a911880c5e045ae9734e3134e5d751\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"text\": \"Creating a dynamic list tool input\\n\\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool.\", \"start_char_idx\": 2, \"end_char_idx\": 507, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a289ce7d-3868-4476-b3c7-b04b6fffff8f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a62c53dbbe33681ff3ce43af54ec4c0c19328db473d060fb7b1f03598cffe84\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c4a8b95-3047-45e6-8e79-8aa5de5ff937\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9c15f32a1dc61ca120516d108764afd1cfc3b4fd35ba225718ff5c7930c6ba32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"text\": \"Prerequisites\\n\\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 238, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a tool input with dynamic listing", "document_node": "{\"id_\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3cebe967-3b58-4f05-9acc-4b816ed796f9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1936ac053e77c95327c1bc7149e8bce2b7e1f7daf68aacac3294d6b850521487\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"463c9b4c-dfa3-47ed-a812-86866d89e915\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d384d58569e0349e6fb902c9897efb0425a99a9b42772b5f07f366f1015d9649\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"text\": \"Create a tool input with dynamic listing\", \"start_char_idx\": 2, \"end_char_idx\": 42, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```", "document_node": "{\"id_\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e969bbff-b1eb-4490-b321-c72e7e471292\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bbf6f556b19f8044dccf35bc5441bc853d43b758c6b30151e64513903af9ff2f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"219011e5-759d-4e47-9efa-3ccbe6a683ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f785c26f9e73736589d948c7ad0a7fc5126016c47ff75c24e12604084f685dc2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"text\": \"Create a list function\\n\\nTo enable dynamic listing, the tool author defines a request function with the following structure:\\n\\n- Type: Regular Python function, can be in tool file or separate file\\n- Input: Accepts parameters needed to fetch options\\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\\n - Required key:\\n - `value`: Internal option value passed to tool function\\n - Optional keys:\\n - `display_value`: Display text shown in dropdown (defaults to `value`)\\n - `hyperlink`: URL to open when option clicked\\n - `description`: Tooltip text on hover\\n\\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\\n\\n```python\\ndef my_list_func(prefix: str = \\\"\\\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\\n \\\"\\\"\\\"This is a dummy function to generate a list of items.\\n\\n :param prefix: prefix to add to each item.\\n :param size: number of items to generate.\\n :param kwargs: other parameters.\\n :return: a list of items. Each item is a dict with the following keys:\\n - value: for backend use. Required.\\n - display_value: for UI display. Optional.\\n - hyperlink: external link. Optional.\\n - description: information icon tip. Optional.\\n \\\"\\\"\\\"\\n import random\\n\\n words = [\\\"apple\\\", \\\"banana\\\", \\\"cherry\\\", \\\"date\\\", \\\"elderberry\\\", \\\"fig\\\", \\\"grape\\\", \\\"honeydew\\\", \\\"kiwi\\\", \\\"lemon\\\"]\\n result = []\\n for i in range(size):\\n random_word = f\\\"{random.choice(words)}{i}\\\"\\n cur_item = {\\n \\\"value\\\": random_word,\\n \\\"display_value\\\": f\\\"{prefix}_{random_word}\\\",\\n \\\"hyperlink\\\": f'https://www.bing.com/search?q={random_word}',\\n \\\"description\\\": f\\\"this is {i} item\\\",\\n }\\n result.append(cur_item)\\n\\n return result\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 2026, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```", "document_node": "{\"id_\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0939118b-828a-4de3-98e9-776c2b8037ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"94f5070b41fbce81858222caf99a4153bd8580851d8f0acf8efaca5417fac9b3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0421518e-cc8e-44dd-aa70-3351f72daa9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7094f1649deac619c5ad713771fdda1d83c52a58ad5223660abecc7a75b12354\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"text\": \"Configure a tool input with the list function\\n\\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\\n\\n- `DynamicList`:\\n - `function`: Path to the list function (module_name.function_name).\\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\\n- `is_multi_select`: Allow user to select multiple values. Default to false.\\n\\nSee tool_with_dynamic_list_input.py as an example.\\n\\n```python\\nfrom promptflow._core.tool import tool\\nfrom promptflow.entities import InputSetting, DynamicList\\n\\n\\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\\\"prefix\\\": \\\"input_prefix\\\"})\\ninput_settings = {\\n \\\"input_text\\\": InputSetting(\\n dynamic_list=dynamic_list_setting,\\n allow_manual_entry=True,\\n is_multi_select=True\\n )\\n}\\n\\n\\n@tool(\\n name=\\\"My Tool with Dynamic List Input\\\",\\n description=\\\"This is my tool with dynamic list input\\\",\\n input_settings=input_settings\\n)\\ndef my_tool(input_text: list, input_prefix: str) -> str:\\n return f\\\"Hello {input_prefix} {','.join(input_text)}\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1188, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.", "document_node": "{\"id_\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"241031e5-137a-4f62-8578-f9ae17176b94\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a22fc60300c108cc9ab2a273d80eab0db119f7e244396d4b27e13ac238703bf4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bf6bba1-a29c-4297-a445-ce4d5a328d1a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa8052b0486384f35c38e76970b87dd604c0216755262c7e3881f02eb7553667\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"text\": \"Use the tool in VS Code\\n\\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\\n\\n```sh\\npip install my-tools-package>=0.0.8\\n```\\n\\n!dynamic list tool input options\\n!dynamic list tool input selected\\n\\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 492, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs", "document_node": "{\"id_\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52cf13ef-f7c7-4777-826e-3436e6fa10a1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f155f38296df1d151acb9003db8e8b02ab7afa2138997d07168a8b16c93ecef3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c79afab1-2fe5-47da-934d-702f4314ec75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97dbc85579e66cc5383b2d74022bff9ebc287c1b88a288a72ee6314262012e4a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure", "document_node": "{\"id_\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2670701d-65c8-4d71-93bf-9dc1af4ebd73\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e363a58b67cb6b64c1d4d39e722c563b324dcd45713d1ea775f43d875d420f54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6825637a-8a9a-46b9-886c-af78c289c725\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"text\": \"I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\\n1. Clarify azure workspace triple \\\"subscription_id\\\", \\\"resource_group_name\\\", \\\"workspace_name\\\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\\n```python\\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \\\"\\\") -> List[Dict[str, str]]:\\n \\\"\\\"\\\"This is an example to show how to get Azure ML resource in tool input list function.\\n\\n :param subscription_id: Azure subscription id.\\n :param resource_group_name: Azure resource group name.\\n :param workspace_name: Azure ML workspace name.\\n :param prefix: prefix to add to each item.\\n \\\"\\\"\\\"\\n from azure.ai.ml import MLClient\\n from azure.identity import DefaultAzureCredential\\n\\n credential = DefaultAzureCredential()\\n credential.get_token(\\\"https://management.azure.com/.default\\\")\\n\\n ml_client = MLClient(\\n credential=credential,\\n subscription_id=subscription_id,\\n resource_group_name=resource_group_name,\\n workspace_name=workspace_name)\\n result = []\\n for ep in ml_client.online_endpoints.list():\\n hyperlink = (\\n f\\\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\\\"\\n f\\\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\\\"\\n f\\\"MachineLearningServices/workspaces/{workspace_name}\\\"\\n )\\n cur_item = {\\n \\\"value\\\": ep.name,\\n \\\"display_value\\\": f\\\"{prefix}_{ep.name}\\\",\\n # external link to jump to the endpoint page.\\n \\\"hyperlink\\\": hyperlink,\\n \\\"description\\\": f\\\"this is endpoint: {ep.name}\\\",\\n }\\n result.append(cur_item)\\n return result\\n```\\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\\n```sh\\naz login\\naz account set --subscription \\naz configure --defaults group= workspace=\\n```\\nInstall azure dependencies.\\n```sh\\npip install azure-ai-ml\\n```\\n```sh\\npip install my-tools-package[azure]>=0.0.8\\n```\\n!dynamic list function azure\", \"start_char_idx\": 2, \"end_char_idx\": 2312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.", "document_node": "{\"id_\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d769cf68-1d72-4689-8a9c-230f570e5cd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f0b39012496db8b16e127cf6868f14f256d4316bf3b5682ae7057f2c021b207f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8ab5c014-a52d-4118-af32-e0b1e321c0f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25051d0b83b48a88302a1bf55761e60a3e1274fb449e748eec202635580ada42\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"text\": \"I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\\n\\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\\n\\n\\\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\\\"\\n\\nIf this occurs, follow these troubleshooting steps:\\n\\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause.\", \"start_char_idx\": 2, \"end_char_idx\": 627, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.", "document_node": "{\"id_\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5e9e5a08-19ff-47b6-b70e-73ece4cea736\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"058be840749f87c3d4c1a9800979db634ce796b011d542b9d12e4b56f07dca74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"941c2c11-092a-49f5-8200-2fa6d93d3f76\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-dynamic-list-tool-input.md\", \"file_name\": \"create-dynamic-list-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 8602, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fb1448cd6054a117bd590f8e8b4114a355e24d3f5f1c39572ad3aee4d3859f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"text\": \"Create and use your own custom strong type connection\\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection.\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections.", "document_node": "{\"id_\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c9f2fdac-08db-4edb-b3c6-a9088b3a70c8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"709f637c22d9b3f7a184550a7328629e9d8e7db1ca51f15982c8e50964ab1d43\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"45b06347-f3bb-45bb-b8cd-4bebfcc8a7d5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f7bd46a9beb665abc290a91f77fa5953f71e2242ec2e2e7990b917fa25c371c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"text\": \"What is a Custom Strong Type Connection?\\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\\n\\n* Enhanced user experience - no need to manually enter connection keys.\\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\\n* Central location to view available keys and data types.\\n\\nFor other connections types, please refer to Connections.\", \"start_char_idx\": 2, \"end_char_idx\": 534, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```", "document_node": "{\"id_\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fab38a19-7a14-4dbd-bab2-26cfcbc1a9bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cc0011738c8a85337bf926c06c918fa10b64f15184d623d4260ff99b5f86b18a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d7de0192-2aa4-4d5f-8b09-de381948dc7c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bb6afd6431375046896846cfba18e8c9277e92a167fc5ba5a085850b2a2a616c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 230, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation.", "document_node": "{\"id_\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79cde2db-d429-4144-9fef-ecf1150f0b58\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef847fe7289c00e59ef01840ff34bece9995f06b5a69fc566387050ad2b15b33\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1b7428b7-afec-4553-b964-11ce173caa88\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5640c1bac73262128b2bdff155125414d600f007e360013f61f21b9514f9216a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"text\": \"Create a custom strong type connection\\nFollow these steps to create a custom strong type connection:\\n\\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\\n\\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\\n\\n3. Document with docstrings explaining each key.\\n\\nFor example:\\n\\n```python\\nfrom promptflow.connections import CustomStrongTypeConnection\\nfrom promptflow.contracts.types import Secret\\n\\n\\nclass MyCustomConnection(CustomStrongTypeConnection):\\n \\\"\\\"\\\"My custom strong type connection.\\n\\n :param api_key: The api key.\\n :type api_key: Secret\\n :param api_base: The api base.\\n :type api_base: String\\n \\\"\\\"\\\"\\n api_key: Secret\\n api_base: str = \\\"This is a fake api base.\\\"\\n\\n```\\n\\nSee this example for a complete implementation.\", \"start_char_idx\": 2, \"end_char_idx\": 883, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:", "document_node": "{\"id_\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7387e95-ab5a-4a70-9c85-229d8acee9fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f3bbcd908601f7bcffce92d9d792b4b62c388bdf1d0303c84e7b579cf80efc9e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2dcd2ba-6db9-44c4-aff2-ee9cdf5e6481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"38053f8e3ddef28b295023d795393f73f2f0287cdb1ce47410fa173f90a75333\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"text\": \"Use the connection in a flow\\nOnce you create a custom strong type connection, here are two ways to use it in your flows:\", \"start_char_idx\": 2, \"end_char_idx\": 122, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow", "document_node": "{\"id_\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a3bd599a-a90a-4cbb-8037-6a13b6dd9c48\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ceaee00a227e4d995d979afa9533af34f51be8bf867a6b10088d37d2a5cca1c3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b179d541-8a09-4574-89b8-a64c273122f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f58715744da5de9078add43af308abab57d0ec0c0312e8053a28721200b89ce\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"text\": \"With Package Tools:\\n\\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\\n\\n2. Develop a flow with custom tools. Please take this folder as an example.\\n\\n3. Create a custom strong type connection using one of the following methods:\\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\\n !create_custom_strong_type_connection_in_node_interface\\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\\n !create_custom_strong_type_connection_add_sign\\n - Click 'Create connection' plus sign in the Custom category.\\n !create_custom_strong_type_connection_in_custom_category \\n\\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\\n!custom_strong_type_connection_template\\n\\n5. Run the flow with the created custom strong type connection.\\n!use_custom_strong_type_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 955, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow", "document_node": "{\"id_\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"289b3241-2041-473c-bb43-232c26f7ad82\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b254e2ca79e4eb95b116cabc8863efc8ecc1d1d1e321860eef0efbe3513b0056\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d76ecad5-c0a4-48be-943d-fd10a7da0404\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7f860b4457d44d0ad46391ebedba7e3c9de8e1be01a8c0503a9ec348461af94f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"text\": \"With Script Tools:\\n\\n1. Develop a flow with python script tools. Please take this folder as an example.\\n\\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\\n !custom\\n\\n3. Run the flow with the created custom connection.\\n !use_custom_connection_in_flow\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```", "document_node": "{\"id_\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9ff5578c-d9c8-4600-8fd2-17be1c3a47bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f490870dcb22fb75d51c9cf96bd148cca6be0f1023c770decb6160254ac5c9a9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f463fb64-d831-4a0b-805b-fb1dbd7e08a8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dae71f4c431a36614eda0be91a611aa08c026705a7041e650273e7a5bff86f4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"text\": \"Local to cloud\\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\\n\\nPlease refer to Run prompt flow in Azure AI for more details.\\n\\nHere is an example command:\\n```\\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\\\proj\\\\github\\\\ms\\\\promptflow\\\\examples\\\\flows\\\\standard\\\\flow-with-package-tool-using-custom-strong-type-connection\\\\data.jsonl --runtime test-compute\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 687, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQs", "document_node": "{\"id_\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ec0fe169-0696-4b09-a1d4-5378bd80aae4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d1005131a9440a9cbe7be4a33e90326f422b8cce59ff3596ce0213b8cc1def9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"53640dc9-a8ad-4340-b619-b167f646ae35\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ed05173aa88b63fe13d93febc31f84ae79f9e4c481d80e8b310dd4b8edd3460f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"text\": \"FAQs\", \"start_char_idx\": 2, \"end_char_idx\": 6, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.", "document_node": "{\"id_\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"696d6411-2b2e-4bae-88ec-df4715c2cb9c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986a6c2ecd58baffe38dd2942c83b8d33b868ae0a3a4a0a718ebc8c9dca4be53\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1cd96350-b9c0-4219-9014-eae10e9cf6f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ddfc4ed783180dde6313aa0b2d0d9635c0816bc0eb70dab26cf309168f1a84f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"text\": \"I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\\n\\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible.\", \"start_char_idx\": 2, \"end_char_idx\": 317, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.", "document_node": "{\"id_\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7fa0f6dc-819e-4c87-8266-b5a9118914d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf6d565ab14197fe3684bddae73d8a73ef4207c61eb95247d99490c74d2d9e7e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ea93d856-ddea-4551-bc52-11321ac3a7b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/create-your-own-custom-strong-type-connection.md\", \"file_name\": \"create-your-own-custom-strong-type-connection.md\", \"file_type\": \"text/markdown\", \"file_size\": 5737, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"076a24d8c039708676c47b768f34e326477fab31b413cb9b8272fe06d047aeeb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"text\": \"Customizing an LLM tool\\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.", "document_node": "{\"id_\": \"60235800-c278-4134-8278-8e27e077672b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6223b1c5-30ec-4887-8019-87b5b08719b0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d4e6526ecfa0dc58bcb2f4ffe54c63f3992a85dd43b94c87bf3443adebc570f7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4ef2e675-a630-4c87-9ab2-04de8eae0dc9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"52ee6047387d2c654b0997f6594724d8e0f94f92b8115d1214e6647d122c6beb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"text\": \"Prerequisites\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 103, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```", "document_node": "{\"id_\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6cf8beb9-6705-40b5-b808-781ec0951cc0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6803b97e70221d067b2043774c8b82ade81fdc957a43c72442bb8d905c46b6b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60235800-c278-4134-8278-8e27e077672b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"550074bef7852df5f5e5336e2075b1a8762712d9439fc0c96f5086cda6c831d7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"text\": \"How to customize an LLM tool\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \\n\\nDevelop the tool code as in this example.\\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\\n\\n ```python\\n from jinja2 import Template\\n from promptflow import tool\\n from promptflow.connections import CustomConnection\\n from promptflow.contracts.types import PromptTemplate\\n\\n\\n @tool\\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\\n # Customize your own code to use the connection and prompt here.\\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\\n return rendered_prompt\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 968, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool", "document_node": "{\"id_\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"82bdb8e8-61f7-4a8f-a7f5-11b155607365\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2cf80cfa83e508b387c2eb96683e4e830b00ddaf57323fd26f63ac87e110d0ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91f741c7-d18e-4df2-bcb0-0972a460c9c5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"063a9ffecfa4b35f71a8fa1211f2c090702e866a378f2ebdefc57d0381cce1b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"text\": \"Use the tool in VS Code\\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \\n- There is a node named \\\"my_custom_llm_tool\\\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \\n!use_my_custom_llm_tool\", \"start_char_idx\": 2, \"end_char_idx\": 410, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.", "document_node": "{\"id_\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9cd195a3-97b4-4a97-82bd-c7d0e87ac685\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"112eaf9f4b6fd25ac3da2887c1935dc9baf039898a60471bebff81abb7c727ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3a8b4084-cfcf-4384-bb1e-dee71c6161a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/customize_an_llm_tool.md\", \"file_name\": \"customize_an_llm_tool.md\", \"file_type\": \"text/markdown\", \"file_size\": 2441, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2981ada939a1138a4a1e90d745140c6d9213160f609c0aeb160899e0b11cb509\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"text\": \"Using file path as tool input\\n\\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\\n\\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 530, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.", "document_node": "{\"id_\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7568039d-4551-48fa-9297-ffb37efc43cf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"59cfa4561fe4293365a4c24a5b539aa6f87ff3607a91d2e043ab8601cec1281a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95499cde-0d4e-4f4e-8802-3e1ef056cd5c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4e17fc4307d1736e16c29afe330d164aa521be82bd5020e7a6c9aa60682efe37\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"text\": \"Prerequisites\\n\\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\\n ```\\n pip install promptflow>=1.0.0\\n ```\\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\", \"start_char_idx\": 2, \"end_char_idx\": 231, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using File Path as Package Tool Input", "document_node": "{\"id_\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"26a93b18-a56a-4cdb-929c-e140981115aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"53b32a0cdc76e7c0bbcc4dc06ef8c4956aa75f189a74a5c1c249410a75f556b7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"07fe0f49-67f4-461b-ad27-9ec18d1a0c08\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"65e17bf0d4970a63c438eb2f24234fc65c5d3607125073f3e84f7d7a8f9e3f90\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"text\": \"Using File Path as Package Tool Input\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool", "document_node": "{\"id_\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ce61fc15-2cdb-4a63-8987-134e03eb1b6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"281ae66cc1678a8b7eab1188b5b3f2f788aae682ca1ab5226c276b1438877cd8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a0c992b5-9555-4434-a1ea-48f7a9a809f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"28319ea3df66083ca8dfeaa86cf9be810cbd1bd26d304edd7da0abbc0cbdb3df\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"text\": \"How to create a package tool with file path input\\n\\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\\n\\nAdd a `FilePath` input for your tool, like in this example.\\n\\n```python\\nimport importlib\\nfrom pathlib import Path\\nfrom promptflow import tool\", \"start_char_idx\": 2, \"end_char_idx\": 328, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath", "document_node": "{\"id_\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"35d2d03c-9329-41d3-8daf-72bc10887d9b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86d6634bc35fe36a0c204adc8d64ddc65da434342731d413778eb0d1a15923f2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"dacda51f-6253-4516-8d44-c10d04cd9f84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b092ede2f91c422d8adccc2b8535ba27c8a11a311ad40a9caee9b642c6c94d98\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"text\": \"1. import the FilePath type\\nfrom promptflow.contracts.types import FilePath\", \"start_char_idx\": 2, \"end_char_idx\": 77, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.", "document_node": "{\"id_\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"333e8f14-0e51-4937-ba22-d6ecd8476ab9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0d3447a096e1bb3aa918cbd4757bea0a31384731c63c27e170e05d8cd82a188a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"291cff59-7387-4f6e-8ea9-cb645ce82f8d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2be8ed1cb5e3cac4ab685a408eb4b16059ca7de35ffdecbd60c7cf76337fa21f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"text\": \"2. add a FilePath input for your tool method\\n@tool()\\ndef my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n\\n return new_module.hello(input_text) \\n```\\n\\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package.\", \"start_char_idx\": 2, \"end_char_idx\": 427, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow", "document_node": "{\"id_\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7015a1ed-1b19-4e4b-9655-112c9e4e9d22\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"11825ea60a67309ba91e6cb42883fb16318dc1f0f387ff5c3698c09b6e09813f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c2c33761-5f40-4c2b-b786-0236f4a25169\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61e24c73f9b4c7d848137d663162585de914a2ce6d445a8fb119dad024ceb8d8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"text\": \"Use tool with a file path input in VS Code extension\\n\\nFollow steps to build and install your tool package and use your tool from VS Code extension.\\n\\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\\n\\n- There is a node named \\\"Tool_with_FilePath_Input\\\" with a `file_path` type input called `input_file`.\\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\\n\\n !use file path in flow\", \"start_char_idx\": 2, \"end_char_idx\": 487, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool", "document_node": "{\"id_\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd07b5eb-b7cc-42a6-ad08-b9576bd69f78\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b1e8f36cab52aa8392c7af80f8578d3cccdb448d4aa2d78149acaa3a2054980c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cd0f9ef-5868-4b19-8e17-2aa272b5f8fb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"30ae50d01e5cb2226fd9eb21587b7269f98d8db6e975d5ac04104b1e6d11d6e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"text\": \"Using File Path as Script Tool Input\\n\\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\\n\\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\\n ```python\\n import importlib\\n from pathlib import Path\\n from promptflow import tool\\n # 1. import the FilePath type\\n from promptflow.contracts.types import FilePath\\n\\n # 2. add a FilePath input for your tool method\\n @tool\\n def my_tool(input_file: FilePath, input_text: str) -> str:\\n # 3. customise your own code to handle and use the input_file here\\n new_module = importlib.import_module(Path(input_file).stem)\\n \\n return new_module.hello(input_text) \\n ```\\n\\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\\n \\n !use file path in script tool\", \"start_char_idx\": 2, \"end_char_idx\": 1206, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "FAQ", "document_node": "{\"id_\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69991809-43a1-45e0-a7ed-543d5244ca8d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d69baeb0f63d28094f13c861f5b2704b30234f6ee523cbf5dbd3e40438e496a6\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4d89e303-0ff7-4a65-a525-4823c35e2580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2ffc12be3b7e8f67357869cf62cdf3b11a723e716507263ba0564f4c8d37e0b8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"text\": \"FAQ\", \"start_char_idx\": 2, \"end_char_idx\": 5, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.", "document_node": "{\"id_\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"412a990a-7993-48bb-8dae-a040894517aa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ef4ca3b0ff6e914f8fe374f18dc27d6bcf687fe1838060a4d95ee76c82ba5bb8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e26d044a-b25a-4a5b-b363-08ac285e3319\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f375989fb7cb098656fd92ec76edb8a6988b562e8611c4cc24231a9ee2a45483\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"text\": \"What are some practical use cases for this feature?\\nThe `FilePath` input enables several useful workflows:\\n\\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\\n\\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above.\", \"start_char_idx\": 2, \"end_char_idx\": 605, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.", "document_node": "{\"id_\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb38a3ca-cfe8-4dca-9b10-2466376b3300\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f471b7d48ccb913477b732b2d731cc7b4f592655595022c777f9e92c1ed4808\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d9f75cf0-025a-4543-a0ec-5ee18d02a901\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/develop-a-tool/use-file-path-as-tool-input.md\", \"file_name\": \"use-file-path-as-tool-input.md\", \"file_type\": \"text/markdown\", \"file_size\": 5033, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0beb23f02b6c04dad63eba913916b5180ea237391724b6b141156bf255136b2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"text\": \"Use streaming endpoints deployed from prompt flow\\n\\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\\n\\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\\n\\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\\n\\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints.\", \"start_char_idx\": 2, \"end_char_idx\": 835, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png", "document_node": "{\"id_\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"706956f6-48c9-41a9-bb1c-da5a86236d6a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3e1a444f441a07ab2df4fd50af04ae49bfb3b215a2bc6535f454b0306e8696e8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"384da23b-5045-4039-b34f-d3b57574cbe9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f20414f2b5fd9f26949d725ab39d59df46f0e6fa135dde4e65ac57ff62940c13\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"text\": \"Create a streaming enabled flow\\n\\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\\n\\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\\n ```jinja\\n {# Sample prompt template for LLM node #}\\n\\n system:\\n You are a helpful assistant.\\n\\n user:\\n {{question}}\\n ```\\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\\n ```python\\n from promptflow import tool\\n\\n # Sample code echo input by yield in Python tool node\\n\\n @tool\\n def my_python_tool(paragraph: str) -> str:\\n yield \\\"Echo: \\\"\\n for word in paragraph.split():\\n yield word + \\\" \\\"\\n ```\\n\\nIn this guide, we will use the \\\"Chat with Wikipedia\\\" sample flow as an example. This flow processes the user\\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\\n\\n!chat_wikipedia.png\", \"start_char_idx\": 2, \"end_char_idx\": 1372, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page.", "document_node": "{\"id_\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6c888e5e-8cc3-40a3-957c-c9490fb07aa7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cf83dc0a7e113999480393c58b334373aff1e4fe2bdbed0ff974e231287e4ce7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a60c32a5-891b-42f0-b30d-ab79f6967ab0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cceee9ac51a91c3744fc3b206e36c00605400633de7103e3a2b2db975be6d42c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"text\": \"Deploy the flow as an online endpoint\\n\\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\\n\\nFollow this guide to deploy your flow as an online endpoint.\\n\\n> [!NOTE]\\n> \\n> You can follow this document to deploy an online endpoint.\\n> Please deploy with runtime environment version later than version `20230816.v10`.\\n> You can check your runtime version and update runtime in the run time detail page.\", \"start_char_idx\": 2, \"end_char_idx\": 513, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:", "document_node": "{\"id_\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98c6ee2b-c91e-450b-964c-eb2654ba13bd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0034781020f8eb762eb657bec70cf919844120f8791674e17ff9ec21750f2c7f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d4018c99-0f4e-4f72-8236-968051671773\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d19eb2cbd0454a1fe365406d6012e7b268cb0a5865166839e9ee8bbccbd109b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"text\": \"Understand the streaming process\\n\\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\\n\\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\\n\\nTo understand the streaming process, consider the following steps:\\n\\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \\\"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\\\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\\n > [!NOTE]\\n > \\n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\\n \\n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\\n - If the `Accept` header specifies other media types, such as `text/html`:\\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\\n > Note: Please refer handle errors for details.\\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\\n\\nLet\\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\\n\\nThe overall process works as follows:\", \"start_char_idx\": 2, \"end_char_idx\": 2788, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response.", "document_node": "{\"id_\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddaf9efd-9ac9-4829-a54c-1648089d8d70\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"680ad8077e320e6e398a84f918cd7befe171f7bb12e18aee8904d3e2647b006f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2ae9478f-2f64-4745-aa96-42f5aade17f2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"073f20a0063371f8009a2ef6f1bc4e1b96f9fc15064212d423408f346883131e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"text\": \"0. The client sends a message to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Hello\\\",\\n \\\"chat_history\\\": []\\n}\\n```\\n> [!NOTE]\\n> \\n> The `Accept` header is set to `text/event-stream` to request a stream response.\", \"start_char_idx\": 2, \"end_char_idx\": 326, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.", "document_node": "{\"id_\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"821fdf27-98c6-43a4-8a2f-c784651596bb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3aabc69a0ec2b4ab4cf0c35722875bb5c3a8751390b1eeafc540cc6ab9fd19d8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5312fd3e-f6a6-433b-9ccb-7a889a6217f1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56295275795aae07ff9f45261683cd2a5fea1ab53b356a90b6ac1edc514468f6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"text\": \"1. The server sends back the response in streaming mode.\\n\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Hello\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" How\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" assist\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" today\\\"}\\n\\ndata: {\\\"answer\\\": \\\" ?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\\n\\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\\n\\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\\n\\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request.\", \"start_char_idx\": 2, \"end_char_idx\": 944, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"912d0e1f-a746-471c-a2a4-71fc2730e575\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d85b5ace9efc60427c9f464f9645bb0589929e638b563f9b7da4c5a5db69026\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d13b07b-6b6c-439c-9416-6df9cfba2f95\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81fdb8216712d1c55035be75ab4899f77f4913243678f92217a6c714e831f153\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n\\n{\\n \\\"question\\\": \\\"Glad to know you!\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"Hello\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"answer\\\": \\\"Hello! How can I assist you today?\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 491, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```", "document_node": "{\"id_\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48347717-5e52-4331-8d92-6a7c54fe3d03\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"554b3afb5397fc0a38ddb0164a88ae48a2e944d9d06f047d66f849aed83187aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b3475a8-13a6-4f66-9230-d9059615ab75\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4489385147c7d3352137222db20b1def0ee36d5064eb647c46c6ba46c9459b33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Nice\\\"}\\n\\ndata: {\\\"answer\\\": \\\" to\\\"}\\n\\ndata: {\\\"answer\\\": \\\" know\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" too\\\"}\\n\\ndata: {\\\"answer\\\": \\\"!\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" there\\\"}\\n\\ndata: {\\\"answer\\\": \\\" anything\\\"}\\n\\ndata: {\\\"answer\\\": \\\" I\\\"}\\n\\ndata: {\\\"answer\\\": \\\" can\\\"}\\n\\ndata: {\\\"answer\\\": \\\" help\\\"}\\n\\ndata: {\\\"answer\\\": \\\" you\\\"}\\n\\ndata: {\\\"answer\\\": \\\" with\\\"}\\n\\ndata: {\\\"answer\\\": \\\"?\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 607, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "4. The chat continues in a similar way.", "document_node": "{\"id_\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ac508813-a33c-4c2c-a3d1-773e79aef114\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6a748b536cb6dbb48de3c2fc76dfaee7b3ac7bb7e92983c1f6a60a2789577178\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1d00d4dc-91a4-426e-b336-54fe61fb7f87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7a1d96756fc67bf7cab9cbf97f7c74fbe85b9b9a23ef9116e8e26ca527c13ea9\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"text\": \"4. The chat continues in a similar way.\", \"start_char_idx\": 2, \"end_char_idx\": 41, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user.", "document_node": "{\"id_\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3fd257bf-5cf8-4f99-bffc-e3bbc6f78390\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"56eac9e90da9529ab6e04074e76b19d92a2b351f7e19b21d8973f970dc189c99\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cd842e43-266f-4657-8635-09ddf99bb1a2\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f5433df6ef98808f332361aa604e4d3c07cbcf3119eb0c73f8279f2e62e3c4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"text\": \"Handle errors\\n\\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\\n\\nIf the response code is \\\"424 Model Error\\\", it means that the error is caused by the model\\u2019s code. The error response from a PromptFlow model always follows this format:\\n\\n```json\\n{\\n \\\"error\\\": {\\n \\\"code\\\": \\\"UserError\\\",\\n \\\"message\\\": \\\"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\\\",\\n }\\n}\\n```\\n* It is always a JSON dictionary with only one key \\\"error\\\" defined.\\n* The value for \\\"error\\\" is a dictionary, containing \\\"code\\\", \\\"message\\\".\\n* \\\"code\\\" defines the error category. Currently, it may be \\\"UserError\\\" for bad user inputs and \\\"SystemError\\\" for errors inside the service.\\n* \\\"message\\\" is a description of the error. It can be displayed to the end user.\", \"start_char_idx\": 2, \"end_char_idx\": 851, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to consume the server-sent events", "document_node": "{\"id_\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6a6fd14f-f375-4da2-a24b-0cafcf1fddf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"efe8860eada88de2417ef06be8a0990d2deea819d95cba2e97b9ca1a432e4c54\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5ed405b3-8e0f-4b2c-aa6f-487c0778395d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a40cdad4aa41441e6e445ec2963ddc5634bac5e233501d25d2937044cb5a571b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"text\": \"How to consume the server-sent events\", \"start_char_idx\": 2, \"end_char_idx\": 39, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```", "document_node": "{\"id_\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dd27869b-15cf-42ca-b7e6-50aa08ba0d32\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7591010f02260b9174a1b2251dc262f58eb1a52ae423e651964800b13059af4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bef8936a-40c5-4816-9f6b-c4c052317580\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d403ff980357db3fc2b3863ad35de0ea021fc125df2f05d417d6bc4209f39c07\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"text\": \"Consume using Python\\n\\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\\n\\n```bash\\npip install sseclient-py \\n```\\n\\nA sample usage would like:\\n\\n```python\\nimport requests \\nfrom sseclient import SSEClient \\nfrom requests.exceptions import HTTPError \\n\\ntry:\\n response = requests.post(url, json=body, headers=headers, stream=stream)\\n response.raise_for_status()\\n\\n content_type = response.headers.get('Content-Type')\\n if \\\"text/event-stream\\\" in content_type:\\n client = SSEClient(response)\\n for event in client.events():\\n # Handle event, i.e. print to stdout\\n else:\\n # Handle json response\\n\\nexcept HTTPError:\\n # Handle exceptions\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 792, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.", "document_node": "{\"id_\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"42e4799e-96c2-4780-a62c-923dc6c72ced\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ee102f88249caf546d0c0bdafd13b8f1a212f9d0775fc8151940e1fee75512c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a26852ca-8a30-4e82-bdc4-18f118702f63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ba8cf573ce6d9c05f2db05e462f18a5093ac7f4cba8a705d93b048300fcdbdfc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"text\": \"Consume using JavaScript\\n\\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example.\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app", "document_node": "{\"id_\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1c8f1f5f-4639-4ce0-a7e3-73399238b474\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3f1b447e5173f4bafc67db22b703f07422d77028dcf992b0553bd73fcd33c9b4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ed2e01b5-e07b-4a16-8c32-c65fc73ec3ff\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d6c4707e0cabbec788712a194de5bb9d61cf9b17218d92b02745f136b9339f3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"text\": \"A sample chat app using Python\\n\\nHere is a sample chat app written in Python.\\n(Click here to view the source code.)\\n\\n!chat_app\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.", "document_node": "{\"id_\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"da359dbe-b196-465f-a58b-923cfa17400e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d36f27b1e6799c33c3a5f8115b7c7535edcea14977513849b56331f899eed90f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"32b0ffc3-9f7f-4498-8a9c-f537824d8a97\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7d714fb0bdd275661313512831d8710c3b5b5fc0e3151dbb76429c4668d5fc36\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"text\": \"Advance usage - hybrid stream and non-stream flow output\\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \\u201cChat with Wikipedia\\u201d flow, you may want to get not only LLM\\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\\u2019s answer and non-stream URL list.\\n\\nIn the sample \\\"Chat With Wikipedia\\\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\\n\\n!chat_wikipedia_dual_output_center.png\\n\\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response.\", \"start_char_idx\": 2, \"end_char_idx\": 805, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```", "document_node": "{\"id_\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"14f0a5dd-312e-4539-b900-5b291142a148\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ed2ed3f2b32332867a54f69c94b86e84eeedfce3c36e9a8010183b04b170e7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"917f8379-0f04-4122-a926-76c9553a6afa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9b897c37922b9b4432a995e5aab44f84d4052da175767aa3dbf868eae1df2b1c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"text\": \"0. The client sends a message to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\",\\n \\\"chat_history\\\": []\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d9f464-762e-4146-9352-9a808af3fde8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"02a6bf0f2539cc26435514fe55f4f59572376600cce1efc190c79b9fcd743123\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"56412e99-fcec-4fb9-9505-9f18a0f5f432\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"47943d7ed1a5ce889f67f6d39d29fb10bf19439b3f5fe545463466aa57679db1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"text\": \"1. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\", \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 747, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```", "document_node": "{\"id_\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"016b2ee8-acf4-4bdc-94c7-79463ab4a7db\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0aa2e2ac63ba13015313fe66dfbb8ec4203540014741ea1281303ddb606424c7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bb1f7729-73ca-4a09-8769-7f5f3825dd6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2a4191605b36ca17f99a19a4b2a44828022ac63f11e0463885ba98774844dde0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"text\": \"2. The client sends another chat message, along with the full chat history, to the server.\\n```\\nPOST https://.inference.ml.azure.com/score\\nContent-Type: application/json\\nAuthorization: Bearer \\nAccept: text/event-stream\\n{\\n \\\"question\\\": \\\"When did OpenAI announce GPT-4? How long is it between these two milestones?\\\",\\n \\\"chat_history\\\": [\\n {\\n \\\"inputs\\\": {\\n \\\"question\\\": \\\"When was ChatGPT launched?\\\"\\n },\\n \\\"outputs\\\": {\\n \\\"url\\\": [\\n \\\"https://en.wikipedia.org/w/index.php?search=ChatGPT\\\",\\n \\\"https://en.wikipedia.org/w/index.php?search=GPT-4\\\"\\n ],\\n \\\"answer\\\": \\\"ChatGPT was launched on November 30, 2022. \\\\n\\\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\\\"\\n }\\n }\\n ]\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 833, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```", "document_node": "{\"id_\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9fe0c1e9-3ca5-4c67-9d7c-bb987940b686\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29379ee510ab86ed5cf7ccd99fa4be6d0d1580d210182a61323bbbd0a9a44089\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a55ab0d9-c0a0-4216-ac59-bf8e138b74ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5eb43caee3fbb59ebac848577b6bd111db761e9c707f9e7c51625ab5c8967cd\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"text\": \"3. The server sends back the answer in streaming mode.\\n```\\nHTTP/1.1 200 OK\\nContent-Type: text/event-stream; charset=utf-8\\nConnection: close\\nTransfer-Encoding: chunked\\n\\ndata: {\\\"url\\\": [\\\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \\\", \\\"https://en.wikipedia.org/w/index.php?search=Microsoft \\\"]}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n\\ndata: {\\\"answer\\\": \\\"Open\\\"}\\n\\ndata: {\\\"answer\\\": \\\"AI\\\"}\\n\\ndata: {\\\"answer\\\": \\\" released\\\"}\\n\\ndata: {\\\"answer\\\": \\\" G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"-\\\"}\\n\\ndata: {\\\"answer\\\": \\\"4\\\"}\\n\\ndata: {\\\"answer\\\": \\\" in\\\"}\\n\\ndata: {\\\"answer\\\": \\\" March\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\" was\\\"}\\n\\ndata: {\\\"answer\\\": \\\" launched\\\"}\\n\\ndata: {\\\"answer\\\": \\\" on\\\"}\\n\\ndata: {\\\"answer\\\": \\\" November\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"30\\\"}\\n\\ndata: {\\\"answer\\\": \\\",\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"202\\\"}\\n\\ndata: {\\\"answer\\\": \\\"2\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\"}\\n\\ndata: {\\\"answer\\\": \\\" The\\\"}\\n\\ndata: {\\\"answer\\\": \\\" time\\\"}\\n\\ndata: {\\\"answer\\\": \\\" between\\\"}\\n\\ndata: {\\\"answer\\\": \\\" these\\\"}\\n\\ndata: {\\\"answer\\\": \\\" two\\\"}\\n\\ndata: {\\\"answer\\\": \\\" milestones\\\"}\\n\\ndata: {\\\"answer\\\": \\\" is\\\"}\\n\\ndata: {\\\"answer\\\": \\\" approximately\\\"}\\n\\ndata: {\\\"answer\\\": \\\" \\\"}\\n\\ndata: {\\\"answer\\\": \\\"3\\\"}\\n\\ndata: {\\\"answer\\\": \\\" months\\\"}\\n\\ndata: {\\\"answer\\\": \\\".\\\\n\\\\n\\\"}\\n\\n...\\n\\ndata: {\\\"answer\\\": \\\"Chat\\\"}\\n\\ndata: {\\\"answer\\\": \\\"G\\\"}\\n\\ndata: {\\\"answer\\\": \\\"PT\\\"}\\n\\ndata: {\\\"answer\\\": \\\"\\\"}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1458, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::", "document_node": "{\"id_\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e02f01b8-6709-4920-9a8b-7e2c5e77be44\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b4fa90920b48a86b6763c89f59b0bddae5ecf0338d4fd85cb546c4cddc5864ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e38e5e0c-5229-4e04-9554-5bd7e77806bd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/enable-streaming-mode.md\", \"file_name\": \"enable-streaming-mode.md\", \"file_type\": \"text/markdown\", \"file_size\": 15633, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e855f94ee43347b7090b34a34228b39211516c0b21c9cbde057c6960d39bc65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"text\": \"Execute flow as a function\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.", "document_node": "{\"id_\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ea36d385-1925-46e4-a5b7-e77f0f3cc6ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6f1f3fd175e8d9c564036921a8f4759cac8cbcb556a37d3504935f460547b059\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f387583-766b-4224-8b9c-34a9cbebe85e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e0dbe73e0b8cca8182fc1aa95271afe9da500ddaf898f2a4a0a00127e69eeb1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"text\": \"Overview\\n\\nPromptflow allows you to load a flow and use it as a function in your code.\\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption.\", \"start_char_idx\": 2, \"end_char_idx\": 228, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```", "document_node": "{\"id_\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fb1e5741-98bd-4b28-88dd-9c503d0421ef\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f813adeab56a408bcb78b566016ee117476fd8356ae2dafe911f856ec3ca07ca\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e0739547-d979-46d9-a25d-97e95bc8e4cf\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"58be6cbe5a2c338cdec7eff10e761c475b5e6c8ba5e0e9bba6d384e04e4ed8aa\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"text\": \"Load an invoke the flow function\\n\\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\\nThen you can consume the flow object like a function by providing key-value arguments for it.\\n\\n```python\\nf = load_flow(\\\"../../examples/flows/standard/web-classification/\\\")\\nf(url=\\\"sample_url\\\")\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 330, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.", "document_node": "{\"id_\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"91e9d667-cfbc-4f4e-9240-09036f81dfc7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bce2f8b33b0e9c233454a16cc5975de252451fb6c45f3ad82274458c869fa0aa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d96764c5-ec33-4e6b-a4ad-dc0d18b7089a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"84c80ceb986071780a9fd1544a1534a3aed222dcf914b468d89af12241f78291\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"text\": \"Config the flow with context\\n\\nYou can overwrite some flow configs before flow function execution by setting `flow.context`.\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)", "document_node": "{\"id_\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"24e752d6-0029-4218-94ca-93a1465077b8\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d7195051357847107c3e1134dd358ec6063a42599855d090ebf34cb8707d0774\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0d3d4ff5-e037-4e24-a43a-b1b24ff711dd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"888bccb53af8fe1b2c8341d34c9a45097227d9fb3376c7918f2760b54e82c725\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"text\": \"Load flow as a function with in-memory connection override\\n\\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\\n\\n```python\\nfrom promptflow.entities import AzureOpenAIConnection\\n\\nconnection_obj = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=api_key,\\n api_base=api_base,\\n api_type=\\\"azure\\\",\\n api_version=api_version,\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```", "document_node": "{\"id_\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dde478bf-d6cb-43a8-b1a4-8d8d35f25e0f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4ed8c2e142e9b716c24dadc03b5b75782fb42f44c8ed62da6f2131b6c418f2eb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"886b63cd-23fc-4885-b6f4-844d4fbe309f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa3a398d9160745661b982f017ccab6950f66f27aa3671391499119e6753ad28\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"text\": \"no need to create the connection object.\\nf.context = FlowContext(\\n connections={\\\"classify_with_llm\\\": {\\\"connection\\\": connection_obj}}\\n)\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.", "document_node": "{\"id_\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a9785096-c148-4ec8-9a62-f6b9f80ef601\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1fcfc555a6a8a8a1950f5352afbdd252f325d853dbef81815bb12d212a5afe8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f263c952-91a3-46b9-83f4-41b46862147b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"524dacfd6de0855b305d213590e27fdbde48bf9a550cb6f44bd7799538432a22\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"text\": \"Local flow as a function with flow inputs override\\n\\nBy providing overrides, the original flow dag will be updated in execution time.\\n\\n```python\\nf.context = FlowContext(\\n # node \\\"fetch_text_content_from_url\\\" will take inputs from the following command instead of from flow input\\n overrides={\\\"nodes.fetch_text_content_from_url.inputs.url\\\": sample_url},\\n)\\n```\\n\\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing.\", \"start_char_idx\": 2, \"end_char_idx\": 565, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\"", "document_node": "{\"id_\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6b681357-4cac-4553-b6a5-9df520eb030b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac1d912138d7d912b5c51e55b4e77d89d14ff84ee46ca9d1ee92acd7d9898b59\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4473f960-693e-42cb-bab8-f0681acfcd9d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5537d4b6817e0608e4b14d6148310463a85fab04d45c1061bd892447357e5e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"text\": \"Load flow as a function with streaming output\\n\\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\\n\\n```python\\nf = load_flow(source=\\\"../../examples/flows/chat/basic-chat/\\\")\\nf.context.streaming = True\\nresult = f(\\n chat_history=[\\n {\\n \\\"inputs\\\": {\\\"chat_input\\\": \\\"Hi\\\"},\\n \\\"outputs\\\": {\\\"chat_output\\\": \\\"Hello! How can I assist you today?\\\"},\\n }\\n ],\\n question=\\\"How are you?\\\",\\n)\\n\\n\\nanswer = \\\"\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 476, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage.", "document_node": "{\"id_\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bbbd143-9995-4367-939e-0c831eb263fe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f2cfa7009b4997d3fde306b94dbf03de21819f05a14d0aaca580fc15eb62a26d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0ce3cb64-7c2e-4bb9-b4e5-d700673151f8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"61dbe9b3c0e4d44cc98923c897f80d38cda4ebbba2a8b786725adffb87ffbb1a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"text\": \"the result will be a generator, iterate it to get the result\\nfor r in result[\\\"answer\\\"]:\\n answer += r\\n\\n```\\n\\nReference our sample for usage.\", \"start_char_idx\": 2, \"end_char_idx\": 143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow", "document_node": "{\"id_\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07fb8988-8ef2-4450-aa41-2d21c42ff60a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a44b5c7aad060be11eb17db2bce6368d458f1e720941d3c50c807c071a6ce513\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"91bceb4d-afd2-4c3a-a02a-8074cd461a9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"593e31da2e356710643de10d98a1b5cb36abc2f47653319d43a1d281d57e2913\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"text\": \"Next steps\\n\\nLearn more about:\\n\\n- Flow as a function sample\\n- Deploy a flow\", \"start_char_idx\": 2, \"end_char_idx\": 76, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Frequency asked questions (FAQ)", "document_node": "{\"id_\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"cb9f4a0f-e680-47fc-8f5d-5b223d51d083\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"743917481836b00908b09ff34a3d165a53a55bbd846807af36b7bb80a22a628c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"307a1aaa-6403-4462-add8-03ad5e5cd75d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/execute-flow-as-a-function.md\", \"file_name\": \"execute-flow-as-a-function.md\", \"file_type\": \"text/markdown\", \"file_size\": 3210, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4183c6717092adc1346ce083b86a3498b50a5b53a656801d00281b0ec33edbf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"text\": \"Frequency asked questions (FAQ)\", \"start_char_idx\": 2, \"end_char_idx\": 33, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "General", "document_node": "{\"id_\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c597cc0b-d110-4165-8c96-53d36acef69d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"814d7155ef3529ff69b2385fcb080cd2c7b7fccacefb5d13c76ea02c151e3825\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bdfdddbb-9577-494b-a219-1d66e74fc39f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1cc8d6407449c53efb0522e02b90a1c8c7bd7d43f714e243e9c5b6cad07be7ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"text\": \"General\", \"start_char_idx\": 2, \"end_char_idx\": 9, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.", "document_node": "{\"id_\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0fe4dd5d-e4c5-40ed-98e7-a044021dbf86\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c1c42f40448725a9a0bd02a07496b82437c4fbad22447c717ff5a6f9ac9b220e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"79b673ef-04a6-4f10-a69b-1b112af9e0ca\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5d9c7de2b8761a812b1360fa456ab60e22fe6453d624543492e0e4cdf0afecd4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"text\": \"Stable vs experimental\\n\\nPrompt flow provides both stable and experimental features in the same SDK.\\n\\n|Feature status | Description | \\n|----------------|----------------|\\nStable features\\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches.\", \"start_char_idx\": 2, \"end_char_idx\": 1143, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details.", "document_node": "{\"id_\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7bb3c750-f12d-4808-ab89-acf161dfd91e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6beadd06f30b207f672c997719c336539e7faf8ef36feaf44e40f65c1b4fa868\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8216d742-4f95-45a3-a653-f29f5ca9511f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"808476072e2d58478fc93d6d1ae4353e8390d76d0859a3a462b7d91ed02867d5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"text\": \"OpenAI 1.x support\\nPlease use the following command to upgrade promptflow for openai 1.x support:\\n```\\npip install promptflow>=1.1.0\\npip install promptflow-tools>=1.0.0\\n```\\nNote that the command above will upgrade your openai package a version later than 1.0.0, \\nwhich may introduce breaking changes to custom tool code.\\n\\nReach OpenAI migration guide for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 369, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Troubleshooting", "document_node": "{\"id_\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e9acc577-1cbb-429e-970d-7c98723202ed\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"af390d4c747d81b170f3d982c0a82884e61001ce8fe19ffbddc01b21b7d24626\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"33bbcc88-5243-4d2c-b29e-5d287b276145\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fd6569c883116eddfbc47c05c0b853af79e907219350c2d48fccecd7b04911e6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"text\": \"Troubleshooting\", \"start_char_idx\": 2, \"end_char_idx\": 17, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.", "document_node": "{\"id_\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6ba934f9-e5d6-4550-8a2f-0c6be54cd508\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8e9e6602be667f9cba044453ac50a9f815cf9662bbf038f534f5481bbbc3305b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9014e5dc-2304-43a8-b458-649c71b86481\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4c10c6c92513df1e8bd280d22ee5b35e204d9e9d4df871513fd387dd9b240f0b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"text\": \"Connection creation failed with StoreConnectionEncryptionKeyError\\n\\n```\\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\\n```\\n\\nThis error raised due to keyring can't find an available backend to store keys.\\nFor example macOS Keychain and Windows Credential Locker\\nare valid keyring backends.\\n\\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\\n`pip install keyrings.alt`\\n\\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring.\", \"start_char_idx\": 2, \"end_char_idx\": 773, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.", "document_node": "{\"id_\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d7499f3d-3746-45d8-bddc-7b8e7726100f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fb9686bc123c832e95558b925d4fb46cc4c621ce1ad04658d3092dc3e77c89\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2fecc81a-33ec-44f0-8402-7a8ec1a439fd\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"986bd922c2ef2b7482c87ed5ce3f8dfce27dc88564dece328fc07c22815ef199\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"text\": \"Pf visualize show error: \\\"tcgetpgrp failed: Not a tty\\\"\\n\\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\\n\\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us.\", \"start_char_idx\": 2, \"end_char_idx\": 367, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.", "document_node": "{\"id_\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0a6a1158-c713-4412-b59d-b85f18e89f0c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"67bd1cc4115725959bb26b2e210e9bc34bdafb0f300364d873e67e7b6d1a203c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"37524ac9-4ec2-4ed3-aeb3-ce3b9b3ef112\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0ee1234eb98b2c6ee0bdc61ccf060a80d9e7365c364d510f64860a94aa69ddec\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"text\": \"Installed tool not appearing in VSCode Extension tool list\\n\\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\\n\\n!VSCode Extension tool list\\n\\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\\n\\n1. Open the VSCode Extension window.\\n\\n2. Bring up the command palette by pressing \\\"Ctrl+Shift+P\\\".\\n\\n3. Type and select the \\\"Developer: Reload Webviews\\\" command. \\n\\n4. Wait a moment for the tool list refreshing.\\n\\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible.\", \"start_char_idx\": 2, \"end_char_idx\": 716, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img", "document_node": "{\"id_\": \"98caef46-1716-47c8-8950-80296635edb6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8b886825-981c-4d7a-a456-b29e07a0f2c3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d6b854d9357a3adff77eaf7bdce41cc3375c66d93c1da46c6f7928d8fc0c13fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5bdc5945-17ce-464e-90ae-851a27126a00\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cea044bb9bda8ce527edde6f82c36059e69f41f71b299be7cea0d7759a6a587\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"text\": \"Set logging level\\n\\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\\n\\n!img\\n\\nCompare to the serving logs with `WARNING` level:\\n\\n!img\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.", "document_node": "{\"id_\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"576f95f6-92d9-483f-822a-0ce9bf0bd395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"45f83f4fb0b797a2d06fb8a2f9cfeb3c6c9008f2be62d661550b4b1311b1934a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"98caef46-1716-47c8-8950-80296635edb6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7dc485967512a5a84236570e34cfe1161c2df0092bf666fa064169f6792f2afb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"text\": \"Set environment variables\\n\\nCurrently, promptflow supports the following environment variables:\\n\\n**PF_WORKER_COUNT** \\n\\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\\n\\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\\n\\nWhen you modify the concurrency, please consider 2 points:\\n\\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\\n\\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\\n\\n```\\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\\n```\\nTPM: token per minute, capacity rate limit of your LLM endpoint\\n\\nduration_seconds: single flow run duration in seconds\\n\\ntoken_count: single flow run token count\\n\\n\\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\\n\\n**PF_BATCH_METHOD**\\n\\nValid for batch run only. Optional values: 'spawn', 'fork'. \\n\\n**spawn**\\n\\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\\n\\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\\n \\n**fork**\\n\\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\\n\\n2. The process starts faster as it doesn't need to reinitialize resources.\\n \\nNote: Windows only supports spawn, Linux and macOS support both spawn and fork.\", \"start_char_idx\": 2, \"end_char_idx\": 2366, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```", "document_node": "{\"id_\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1bb38f65-df51-4e35-9339-b39205a74d42\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5ffb3a0055a7127117140f63d34e4ee966af213db99b4fa728c673465b4004c0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"01f0c16a-b242-4bd9-a0b9-36f5c673d03a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2918d5c5af6abdfa64690760c5e83327eb7534212ac0b79bde3d1631e1a91c1b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"text\": \"You can configure environment variables in the following ways\\n\\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\\\"2\\\" PF_BATCH_METHOD=\\\"spawn\\\"```.\\n\\n2. If you are using SDK, you can specify environment variables when creating run. Example: \\n\\n``` python\\n pf = PFClient(\\n credential=credential,\\n subscription_id=\\\"\\\",\\n resource_group_name=\\\"\\\",\\n workspace_name=\\\"\\\",\\n )\\n\\n flow = \\\"web-classification\\\"\\n data = \\\"web-classification/data.jsonl\\\"\\n runtime = \\\"example-runtime-ci\\\"\\n\\n environment_variables = {\\\"PF_WORKER_COUNT\\\": \\\"2\\\", \\\"PF_BATCH_METHOD\\\": \\\"spawn\\\"}\\n\\n # create run\\n base_run = pf.run(\\n flow=flow,\\n data=data,\\n runtime=runtime,\\n environment_variables=environment_variables,\\n )\\n```\\n\\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\\n\\n``` yaml\\n name: flow_name\\n display_name: display_name\\n flow: flow_folder\\n data: data_file\\n column_mapping:\\n customer_info: \\n history: \\n environment_variables:\\n PF_WORKER_COUNT: \\\"2\\\"\\n PF_BATCH_METHOD: \\\"spawn\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 1240, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it.", "document_node": "{\"id_\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2d12cb4e-9982-46b1-8020-5a397a5c70ee\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27490f9ccc0a4ef12bcef73484eb8f041e969282c05eff50bb23a31b4394ca93\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"81f269a5-0f9a-40ed-9be9-ffb962df58c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/faq.md\", \"file_name\": \"faq.md\", \"file_type\": \"text/markdown\", \"file_size\": 8177, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4f748801ca1f2b60ea042a606fecc4e918c6c1a3f27b167307355a5f06103791\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"text\": \"Initialize and test a flow\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nFrom this document, customer can initialize a flow and test it.\", \"start_char_idx\": 2, \"end_char_idx\": 208, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow.", "document_node": "{\"id_\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"223ae55b-31d0-4a3f-a845-e2cbb48d2174\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a987c0ab8aa00ab20a17431c70079e376558edd598e742211a1b6d6323108503\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"39781833-ad92-4d69-ae7c-fdfba0b36710\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6c6abfe3b1deba2ae793d908042c49b4ec9b656dd92fb96c4c7f199257f4e02f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"text\": \"Initialize flow\\n\\nCreating a flow folder with code/prompts and yaml definitions of the flow.\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3a5ad4e4-84f4-4725-8096-3096c1ce097f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9d2f6bed32465c8afd0d71f4ff8109ac9daee9f05c58a3b9afe2016bca66aa5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"60098afd-5817-4612-b0da-b6b01eb4d302\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2c35710a07df93b5af600ed64e76b7f3b22644cf67560a88ace8cc5fb49a6be8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"text\": \"Initialize flow from scratch\\n\\nPromptflow can create three types of flow folder:\\n- standard: Basic structure of flow folder.\\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 525, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a flow\npf flow init --flow", "document_node": "{\"id_\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a66b4440-7ab7-4a0a-8e3e-cf53ce0da183\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c55a21ae37e2c8abc954550c17e8d4ae89c001cbd51afbdf6250026ab8111cd7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8cb76d9e-035c-42fa-9a88-f708905d7d06\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"20fcc6e583168eb3eaea314fba27fc29dc4accf1f6ade95c5244647052ad85c2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"text\": \"Create a flow\\npf flow init --flow\", \"start_char_idx\": 2, \"end_char_idx\": 35, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder", "document_node": "{\"id_\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3979a8ce-fe87-4ab5-b144-4b734aa35c25\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"184c77063135f92e2154daff06d061bfd4a0dc94f3d65875b712e2986daca02a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d28162a1-81fa-41cb-8f50-40ec0b266596\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae4c5189ec3559cebc3b564d2e16742db6a99d99bf9da9cf9d01817c74429599\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"text\": \"Create a chat flow\\npf flow init --flow --type chat\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse VS Code explorer pane > directory icon > right click > the \\\"New flow in this directory\\\" action. Follow the popped out dialog to initialize your flow in the target folder.\\n!img\\n\\nAlternatively, you can use the \\\"Create new flow\\\" action on the prompt flow pane > quick access section to create a new flow\\n!img\\n\\n:::\\n\\n::::\\n\\n\\nStructure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n!init_flow_folder\", \"start_char_idx\": 2, \"end_char_idx\": 847, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash", "document_node": "{\"id_\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"15bc22d5-c272-430d-b04a-79cfe65f18fd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"66785e16e82b7ffa50adb19068670cd130f8b3dc6ab081a908061308b313ce3c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f08deb4d-4999-4477-bb42-7d275b6210f3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e046dd55aa763af2644d78d8f55299493f07a917b05675118277d6c46f6655ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"text\": \"Create from existing code\\n\\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 414, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files", "document_node": "{\"id_\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8a15b7b7-5711-4d86-917f-4fc2036c6027\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6c03c3df69e37b72e57a0a75ca81f10041bf1c7f5b9b1a3c8506b13f6aa43f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d2d01ef-f872-422b-93d4-c74821d338aa\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"432c1e3212e900e32c8d1ba555ce85b918447c43cf887279f9a62fb0d9f62c10\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"text\": \"Create a flow in existing folder\\npf flow init --flow --entry --function --prompt-template =\\n```\\n\\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\\n\\n!init_output\\n\\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\\n\\n!init_files\", \"start_char_idx\": 2, \"end_char_idx\": 396, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.", "document_node": "{\"id_\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"95cd3374-d155-4f86-b29d-fb4bf987e22b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9422effd2aaeb2748e289c5baf349916d999564c3179e620610f11eb42dd375e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7d0dfc7a-e83c-4128-828d-81c533373072\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b9c4ccc217f568ae7762dfa04756929d0d48f4baa6b89fc6a83ca59bde05a6bc\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"text\": \"Test a flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow.\", \"start_char_idx\": 2, \"end_char_idx\": 363, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::", "document_node": "{\"id_\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2aafc740-6302-4dbf-a42d-ee1dea0c6ebf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"446896168b129cd5539cb3091ff4073483ad34e324321c181d6a0901e0abd70a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"15411bff-c55e-4f94-9f49-2c92b7acbe5e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8db5458f51f44a2327136b2e840819c66477032d51a2e2f6e33fa3ae2cf79f26\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"text\": \"Visual editor on the VS Code for prompt flow.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \\\"Visual editor\\\" action. Use it to open the Visual editor with GUI support.\\n\\n!img\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 300, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash", "document_node": "{\"id_\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ee0cc84-3f98-42e6-8a67-fbdee3586ccc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b83ff835b3a805eb03482d718707c0e686d12752df5f55dce13fd7e2fcaf50a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"48c09cff-1766-4dd5-8c9a-61462db60876\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"306eb518a1098e7de68d3e20dac568551c1758d95e2c0fb43d6a4fa155324b2b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"text\": \"Test flow\\n\\nCustomer can use CLI or VS Code extension to test the flow.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\npf flow test --flow", "document_node": "{\"id_\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd5cefe7-28c9-4bf0-9fc6-8b3609de5b5a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"229f3f16a238a91b31c7e47ac2e91406ec163f09cd791edd3eb594209a03c0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78879b5d-1518-42b2-bdd4-edcf82e38d0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c7f140293b9c1a50fa9a6a2d8336acf046e98c1fedf93a78d336016da3eeff91\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"text\": \"Test flow\\npf flow test --flow\", \"start_char_idx\": 2, \"end_char_idx\": 31, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"49dd7bd1-552d-40a9-8f03-e533f0e08d54\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ddf2f5446188a40b24a32a024a1b0544334ba529ecba86dda4f49f1d4be2129\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d12e900d-e14e-4e31-a997-e651c014b50d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"25505195686c732851f290a4484edf6adc23cd65daf213d5b1b7b1e3cb0faceb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"text\": \"Test flow with specified variant\\npf flow test --flow --variant '${.}'\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 577, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d1ad1393-927d-41d6-8139-7e599f0f06e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"89b24a887590553199b9ee0c1b9fc51a85ab692e6db323dbdcd22c2255e9a892\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e382a39f-025e-49e0-9619-8115401f834f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a2541ca9409d4dba8d671a89fdcf477b6d9152cf048fde6c6f5dab29479fa65e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\\n```\\n\\nThe log and result of flow test will be displayed in the terminal.\\n\\n!flow test\\n\\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\\n- **flow.log**: The log of flow test.\\n- **flow.output.json**: The result of flow test.\\n\\n!flow_output_files\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 702, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash", "document_node": "{\"id_\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b4eb28b8-dc68-48de-87fe-746453fa405a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"125b62feb2a0b81e72c1bbb54a25128fe0ef760e2cf21a4de506ac04bc14cc5e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aacd779-e39c-4a33-b22b-6401b84395a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a8494ad1203472d748abf396cf3ae8ce1fe6d9ed84a986d81ded14805d393f15\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"text\": \"Test a single node in the flow\\n\\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nCustomer can execute this command to test the flow.\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 337, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7b80b991-92a3-41ea-a747-36708cbc9dd2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68553f1861f970ef898e05440d384d9c431f59f1b74bb863b93bba6b233fac22\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a45a39ff-cd5e-48f8-a762-f0c340c35045\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e27309d486497cb6b4d219bab5a7515e637175aa60f0e4c84b767fc18e65973e\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"text\": \"Test flow node\\npf flow test --flow --node \\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 419, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"18f1adbf-ecc3-4b53-8418-89329a15ce5e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"cd07e53bbd4061d9ac9e11b6f588c17761eb7b3a19c7444a286fc89370fc0325\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0aca58bb-fa4c-4a32-b8a6-c18a7ef46e0b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"da0542763f1fc5b4af88855ce469dfaba93b96c80a5a9a572b690e5f8e113630\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"text\": \"Test not iun the flow\\ninputs = {: } # The inputs of the node.\\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 533, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash", "document_node": "{\"id_\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bd754830-349c-4e11-a781-bb24512461e1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3d66f9f55eb3364c049a109ae76e0f366d5b39f746f9732b4cc63961d184d1b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6fc25b47-e9a6-495f-a403-7c7e5e9f3722\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"aa441889ac5b03eb8982f27ff9ae8efb3bef745148e8f19ed986373c865c0bdf\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"text\": \"Test with interactive mode\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 234, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()", "document_node": "{\"id_\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"1dfba4cb-27ff-46d4-9f89-6e585c66e7af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"15964bbe99b83f7830453b5a2e5113f3bef996cda9aa8ef777a98643873a429f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9072a080-44f8-44c3-af27-7b8c2d4d3fd5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5c3bd3e4e29c1bb30585294c9dc305126e095d5cd3b443bca97af562296263a8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"text\": \"Chat in the flow\\npf flow test --flow --interactive\\n```\\n\\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\\n\\nUsing this chat flow to show how to use interactive mode.\\n\\n!chat\\n\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\\n\\n!img\\n!img\\n\\n:::\\n\\n::::\\n\\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe flow result will be streamed in the terminal as shown below.\\n\\n!streaming_output\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf_client = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 1162, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::", "document_node": "{\"id_\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bf5960ff-bb2a-46e1-91ec-56aca552ecbd\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c8c2606c9b6fb9f5472c28e53817c83a807118199ca561ac221ee50d994050db\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0cc9446b-4b86-4460-971d-67a653543ac9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64c4ccfc0dc788faa39ca8300a634ab29d76c825a121603d2cb6bb44773300ca\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"text\": \"Test flow\\ninputs = {\\\"\\\": \\\"\\\"} # The inputs of the flow.\\nflow_result = pf_client.test(flow=\\\"\\\", inputs=inputs)\\nfor item in flow_result[\\\"\\\"]:\\n print(item)\\n```\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 169, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::", "document_node": "{\"id_\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bdc16d88-1916-4304-a6f7-440c9efca1ca\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"82e4d3ca19496b8c5d4386adfd56d7eaa8cc032e8c7c141ef4c7e886eef46caa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c0f9bc73-3d7c-475a-941f-0d2a1204ae84\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b7ec9aa5ab529bb2b138816b410933849258f23be7660fcd825a9e8428155b08\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"text\": \"Debug a single node in the flow\\n\\nCustomer can debug a single python node in VScode by the extension.\\n\\n::::{tab-set}\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\\n!img\\n!img\\n\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 374, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\n- Add conditional control to a flow", "document_node": "{\"id_\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d5caefb5-8563-48c6-814b-b513309e144c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"86f72212dd70181df51676601190b6b412486d8aeeaeca9885371345ea964535\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"af2d8e48-0624-4c35-ad8f-dfa08cf6c27c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d05a97f2533a02784f5c1b69640196def0413e8aa7c3d24888afedeaa265c481\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"text\": \"Next steps\\n\\n- Add conditional control to a flow\", \"start_char_idx\": 2, \"end_char_idx\": 49, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::", "document_node": "{\"id_\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5c679040-3627-4e7a-8599-ae144332c763\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bc0144e32aa85d7452b6071e6e0ac610d0995a2640ead996bc906162475a7c77\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cffa6e02-6a71-4676-bc7f-7de915c6d10d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/init-and-test-a-flow.md\", \"file_name\": \"init-and-test-a-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 10466, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8f8ae40dc2c73b8c421c0990ae3ae563aec7384370c6d32ec6cdcac2fa48432f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"text\": \"Manage connections\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\\n\\n:::{note}\\nTo use azureml workspace connection locally, refer to this guide.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 422, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.", "document_node": "{\"id_\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7c4ff6b8-fe67-4ec7-9eea-a84769ed42fa\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9fc840fdb46639dfa7f2c0c5525c7397a8b717192d4e4fd05796d2a5443e72d7\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7181bb78-1650-4f0c-ab33-1a6ba0691e8c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08a8b59e3402de3091cfb74ee4a24ea2efb0d88f206acdb30b7d47f496d58f11\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"text\": \"Connection types\\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\\n\\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 502, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash", "document_node": "{\"id_\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"48897b0d-44af-4c0a-8411-f4048af44ce9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"849f9eedece63c894efdd476e9e1bb3dde2e5c55044c6a782b51bf3bb4b48b7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f9b09f6-b7f1-4fa4-b974-41dd8f55b17a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e5e3bf260e8c95a1c452a19a8e4f746dacc441d68bf1921e813d3d4ca2b1b9e0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"text\": \"Create a connection\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: azure_open_ai_connection\\ntype: azure_open_ai\\napi_key: \\\"\\\"\\napi_base: \\\"https://.openai.azure.com/\\\"\\napi_type: \\\"azure\\\"\\napi_version: \\\"2023-03-15-preview\\\"\\n```\\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\\nname: custom_connection\\ntype: custom\\nconfigs:\\n endpoint: \\\"\\\"\\n other_config: \\\"other_value\\\"\\nsecrets: # required\\n my_key: \\\"\\\"\\n```\\nAfter preparing the yaml file, use the CLI command below to create them:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 1078, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key=", "document_node": "{\"id_\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"87222c5e-4f77-4b93-8d69-d5f7af5f06f3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0e4402c636bd9dd666a5652039e3f48b4f98339d223f75428020f237415d64fa\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"74687803-6c5a-463d-9a20-c5f1a6f92a47\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"32c472763f52f52f1f1beebac695ed9e3cbabbfa3d8dccadf31032f17ad0c228\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"text\": \"Override keys with --set to avoid yaml file changes\\npf connection create -f --set api_key=\", \"start_char_idx\": 2, \"end_char_idx\": 93, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection", "document_node": "{\"id_\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"415192cd-10f2-45df-b939-9de5ea5c8ee0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d9fac2f2493f493188f30ca653a58bf91bee6219703e2123ffaafdb01a378519\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"52bf1ccf-b8cd-4073-8d0a-bfd092cf9a67\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"009c9c62093e07497a7c96111adae39109027362bb33c96d020019e01bf0789f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"text\": \"Create the custom connection\\npf connection create -f --set configs.endpoint= secrets.my_key=\\n```\\nThe expected result is as follows if the connection created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5ac1b34a-f365-46b2-af27-98df27795edb\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d704aa2ec218d1b1acc8c01252d81cd49440df151dd5ec4a92ccf0fbb54a87ff\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c280afc1-0e64-46b5-ac1a-c2d76239112e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e05c0245306f0f4704a139f86b27f001a1d45a39850e0415bec44306a3ea2b02\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)", "document_node": "{\"id_\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"ddfa8c7c-cdd4-4073-ad8c-34534a20b49a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a7db8e137fd4c7c07d1f4ae406b7ee0b2aad89be313957c12e3d2c9efdf5538\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"18920e5c-3a41-489b-9796-da47be810e87\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"text\": \"Initialize an AzureOpenAIConnection object\\nconnection = AzureOpenAIConnection(\\n name=\\\"my_azure_open_ai_connection\\\", \\n api_key=\\\"\\\", \\n api_base=\\\"\\\"\\n api_version=\\\"2023-03-15-preview\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 193, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)", "document_node": "{\"id_\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"86e2c793-3cb8-4ec7-bc7d-44576f1a8170\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0a0e5bcab0cc6aca9da6836e7fd11cd9442b42270019b48113f33540fb9d8d40\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"e7785c31-f443-4ee1-9730-eae67b71e7b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e3f84532e04af35b646abfe8ad774f3049bb6aa726480d2bb09ff1c9203a373\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"text\": \"Create the connection, note that api_key will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)", "document_node": "{\"id_\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a130569c-c523-4a83-be04-b4706f124c1c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"011cb400a1083e76cc32cc921b1a71a76b18dde3df75f4b224a9b9e1d9434f90\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"bae2e6b9-9dbf-4be9-b1a8-796bedb7ccb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"de6f45ed8013591a29e2f5f9a6b4cbd7170f67becce8256ad96d9c40fabd1417\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"text\": \"Initialize a custom connection object\\nconnection = CustomConnection(\\n name=\\\"my_custom_connection\\\", \\n # Secrets is a required field for custom connection\\n secrets={\\\"my_key\\\": \\\"\\\"},\\n configs={\\\"endpoint\\\": \\\"\\\", \\\"other_config\\\": \\\"other_value\\\"}\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 250, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e783be9d-0148-44a5-ab4f-dd0523ac8334\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"751dfc933b0e96e74f8ce306a449da30d196af0146bd2bf18261f765194c180f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"fd64059d-790d-48e8-a7b5-34aa2fefd748\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e5cfc0de00cdb147bac6b8391cf58054d90a8bb1d51c4fa5aaf880856fe3cb4\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"text\": \"Create the connection, note that all secret values will be scrubbed in the returned result\\nresult = pf.connections.create_or_update(connection)\\nprint(result)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \\\"+\\\" icon on the top right of it and follow the popped out instructions to create your new connection.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 463, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash", "document_node": "{\"id_\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e85cc25f-3348-406f-af8a-2754d2339ac3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8ff8b3d46333114d6aa64b7572fc631715461e38af0f2ddf90f5bd6ceefe0483\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"332d8cce-bb77-41e6-92b9-199d246157a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"19bbe4885c51f618700653cdb87a444a9e16d7d215fa7c1e26ab5fb47708072a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"text\": \"Update a connection\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nThe commands below show how to update existing connections with new values:\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 149, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'", "document_node": "{\"id_\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3abffd3b-ed39-4218-bce7-5becbd65db6c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"74e7f2cb5f8df53cffe2b8bf20c9755b3e0cd188ab67d8f242d74e36cd2d5773\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8724bb59-ea5a-405c-a27d-08fc2de8bd9a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e7488ea710284ba1a55be6c4b52debc56839f2fbd23f7c61b848f80cc093736c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"text\": \"Update an azure open ai connection with a new api base\\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'\", \"start_char_idx\": 2, \"end_char_idx\": 135, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python", "document_node": "{\"id_\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"50207311-5c91-4251-a254-720a7b40926a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"73a939ef359ad24d3ddae75e1280b2e91a6cca8a37caa45b3b798800a099da3a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a24e144b-3ea8-4b7f-9a12-1a8b42377767\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"590544c750fbe84c364e3f930c091988ad8c9c0de18b6cf33c47949dc576d1a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"text\": \"Update a custom connection\\npf connection update -n my_custom_connection --set configs.other_config='new_value'\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nThe code snippet below shows how to update existing connections with new values:\\n```python\", \"start_char_idx\": 2, \"end_char_idx\": 242, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)", "document_node": "{\"id_\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c76ef7e2-4457-4746-aa80-44d36f3e679d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5e529352592a59587b997627812a31f186d8aad0960591837b21f31fcca158ea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3fca2522-e7ab-4b07-a8a3-3d3b887e931a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d16a16f8119def0fadde3f628972538fda9ea7e334ad5d022e87e164e13be258\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"text\": \"Update an azure open ai connection with a new api base\\nconnection = pf.connections.get(name=\\\"my_azure_open_ai_connection\\\")\\nconnection.api_base = \\\"new_value\\\"\\nconnection.api_key = \\\"\\\" # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\", \"start_char_idx\": 2, \"end_char_idx\": 312, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"63dd3856-a79f-497b-a8e0-aa61b446d692\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a5025c879a00830a327e4ec3f23a86b5566cb9fa543823d37bbe40e4c5cec352\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0b4d3258-2cfd-46ea-8bd8-963417cdfc12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ca9fa7979e1cfb70575eb085e9bdb081564a9b0fa850a534182f4cf3ac21b8ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"text\": \"Update a custom connection\\nconnection = pf.connections.get(name=\\\"my_custom_connection\\\")\\nconnection.configs[\\\"other_config\\\"] = \\\"new_value\\\"\\nconnection.secrets = {\\\"key1\\\": \\\"val1\\\"} # secrets are required when updating connection using sdk\\nresult = pf.connections.create_or_update(connection)\\nprint(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 574, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5f6d9da7-52eb-4abf-8a2e-a927ee735541\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d3ea86a42100eb1fe366be6811c4eeaac9dfb41944fb89ba80ff1b66f248a615\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5b591196-6d18-4a7c-a2e1-2c0b0da56f0e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"97ace713129d887dd572eda150e464cf121aaaf745f984a9641d9765b2a72f01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"text\": \"List connections\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\\n```bash\\npf connection list\\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 415, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f51d9a42-127f-4ea9-9792-e149e8a38a7e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d19ed770-3ae7-4b38-b66e-5c45134d9586\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"76503327b02a26de2806df7694b03a3ee13f52876c9835e0a792988e4a2ba019\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"02057374-00f7-431d-9da0-156db1202852\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"5700cd94662430caae88bb657f1bca9ea785a2616bc964557182744191e247dc\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ad0fd199-68b4-4a11-aa38-2ff3915a4f93\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"text\": \"List and print connections\\nconnection_list = pf.connections.list()\\nfor connection in connection_list:\\n print(connection)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 191, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9829818d-2389-4b7a-b824-87ff80e4e5bc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"50527ec74e94bfc190f0dbf98b325f1f2e187c5ac5ec86d7a09dfee41c9592c4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9f132951-73d5-4273-950d-fc9b0a48c9d6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f578c391a330e6a3b2e99118cbc01bbfed4c0eab545f2dd11d99e84b7bd5a67d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"text\": \"Delete a connection\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nDelete a connection with the following command:\\n```bash\\npf connection delete -n \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nDelete a connection with the following code snippet:\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 279, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage connections\npf = PFClient()", "document_node": "{\"id_\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e31a56f7-dfde-4662-a545-e3382f5d2395\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a74a195c7da9c110bd1be916a90036ca632b4326e68080ac11c215856df7b0f5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a2490f5-6240-4e75-bc37-936f5be9f8a7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"411abad4a36435115cd73256af6e112b7ff83979f1f4ab18eb9ff325cee36070\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"text\": \"Get a pf client to manage connections\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 55, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::", "document_node": "{\"id_\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"09e1d45a-e995-4845-9819-61a50a7e3fcc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62a9b42d19dc3a2618a57b3123475f3e48b57c65cef1d43fd9918153ffb040ba\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c7e153a3-d400-4557-bc4f-f7d0d0018151\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f41c1446f9248f33e4d120b822d8e1c8fd40dcb94795428736f8b615ec7a575d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"text\": \"Delete the connection with specific name\\nclient.connections.delete(name=\\\"my_custom_connection\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 365, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI.", "document_node": "{\"id_\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"345ef80f-a13b-4a7a-a85c-fcb140faf879\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3d5386667d921191043732d28b80d2062181886d4c8ab54880eaed2e9a80f6a0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"80eaa086-d94f-4139-8000-d575de0852e3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2b6d29e1aa11177bb5f27f1ea4d5d0f84649d797a86aa70e2ea79c58342f5904\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"text\": \"Next steps\\n- Reach more detail about connection concepts.\\n- Try the connection samples.\\n- Consume connections from Azure AI.\", \"start_char_idx\": 2, \"end_char_idx\": 126, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run", "document_node": "{\"id_\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bb5ce587-ed3b-4933-90a2-cd69af33569a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f5704af61f5056221d2e79bc09b64b5866186f2a9d92c1973198f7ad601ff0c2\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"86742abe-4594-4ae1-b4a4-a35ac63e7803\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-connections.md\", \"file_name\": \"manage-connections.md\", \"file_type\": \"text/markdown\", \"file_size\": 7843, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f60dd93c883bd9552ff6b6bda68c4875a92206c9bc214bff4f917849c3b1f0ef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"text\": \"Manage runs\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \\n\\nIn general:\\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\\n\\nLet's take a look at the following topics:\\n\\n- Manage runs\\n - Create a run\\n - Get a run\\n - Show run details\\n - Show run metrics\\n - Visualize a run\\n - List runs\\n - Update a run\\n - Archive a run\\n - Restore a run\", \"start_char_idx\": 2, \"end_char_idx\": 668, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash", "document_node": "{\"id_\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2f925fe9-ce2c-4854-b77b-13180f4a0960\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2128e989c9a49e28690407060252f2ed66ab45c3e599f65cfcd28e80fa2cdde9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2afc7981-f82b-4315-9b61-a45e03c74e6c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3387bcf696a05a58f4785cf0447d34eb5a2d3f7d7701f3ccea1b0dd0980ed2ac\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"text\": \"Create a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\nTo create a run against bulk inputs, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../web_classification\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n url: \\\"${data.url}\\\"\\nvariant: ${summarize_text_content.variant_0}\\n```\\n\\nTo create a run against existing run, you can write the following YAML file.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: ../classification_accuracy_evaluation\\ndata: ../webClassification1.jsonl\\ncolumn_mapping:\\n groundtruth: \\\"${data.answer}\\\"\\n prediction: \\\"${run.outputs.category}\\\"\\nrun: \\n```\\n\\nReference here for detailed information for column mapping.\\nYou can find additional information about flow yaml schema in Run YAML Schema.\\n\\nAfter preparing the yaml file, use the CLI command below to create them:\\n\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 940, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create the flow run\npf run create -f", "document_node": "{\"id_\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e8f49d4b-09cb-4725-b400-3e6a57e6f756\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1f5b6613de87d844d48e200c9b9c9059eeec4f91a3db91eecb7cdab65d19814c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d822ae-280d-459a-bc57-15f8380292b6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e4786e19b97458564a27f48a7b129ee055e6ef5be52e56117e017bd43d2daba2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"text\": \"create the flow run\\npf run create -f\", \"start_char_idx\": 2, \"end_char_idx\": 38, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run", "document_node": "{\"id_\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"69b30e6f-ae04-4662-b070-0d2f621ebefe\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4633642239f0ea5e8c401ec55305ae8b31da7edc8a8b8d683eb99d6fe9106406\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d3556bf8-f5ee-4b3b-992a-086d3fe5d806\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"673b9274e9617593898a80a78349c1a63c95838d9df9ee99af1f5c87adee04fb\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"text\": \"create the flow run and stream output\\npf run create -f --stream\\n```\\n\\nThe expected result is as follows if the run is created successfully.\\n\\n!img\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import Run\", \"start_char_idx\": 2, \"end_char_idx\": 409, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7d2a225f-8af5-476f-89c9-80c92eeb0470\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad254fb5c3bfa9051eb14e7387114c2a5c1c76bbb931108fe180d2bb19b7054\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9faa491a-3a00-46a2-95db-2098124d4516\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"83b766b8f35937b17c83373b4b2dd9369406d873bc674ccc80ebc1a52a4b076c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)", "document_node": "{\"id_\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"fd6f0ea0-d59d-4713-9cd0-ba3eb0e65942\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"48b09a6ad917a748e77953d709c4a0363847b171256aca5776de986d2a3403cf\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ae707a31-2fd9-489b-b37a-f8a580145c09\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"text\": \"Initialize an Run object\\nrun = Run( \\n flow=\\\"\\\",\\n # run flow against local data or existing run, only one of data & run can be specified. \\n data=\\\"\\\",\\n run=\\\"\\\",\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n variant=\\\"${summarize_text_content.variant_0}\\\"\\n)\", \"start_char_idx\": 2, \"end_char_idx\": 264, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::", "document_node": "{\"id_\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d537c095-e0b4-4578-bd01-a7a6ecfdaa26\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dbdad1ed5255e045338bc1ee9997c8440345b0219f5f7c566599525647199619\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"cb7b5d4a-62b0-4405-b55f-dca5344d09b8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"36106119244db88c0a41587812521a455eaa9f4b98fd401ac1d17ee1e36abd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"text\": \"Create the run\\nresult = pf.runs.create_or_update(run)\\nprint(result)\\n\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\\n\\n!img\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 301, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aa7fb66b-5547-4381-8445-5b889fbd750d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"670696330b3c61d1dd01ad6a0443001a2420bde7594a46160f3014ae731abb72\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"700e1a44-d276-4480-be73-85a4d2eb4a12\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7e9eaf046083bd7df11aad7b03172c4d9e310e4764d07904fdda4221fad35592\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"text\": \"Get a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet a run in CLI with JSON format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 233, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f49dcc8e-cb73-4d39-9315-4850fbf8574f\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e89ebd2-0566-4a74-933f-8b82bd4a00a6\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d51a57970326e6949d1ce409aacab5647be8f5917adf196731bc68e0fe92118c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4fd00d1e-3ff5-4e22-b9f3-6b9035a840f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b3bab73b36683da5ccd33b89ba1de7fe035ca591a43a5a2a2343c5ff007be74\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20ebfb15-7b02-47b3-bd72-b5f836d84641\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"text\": \"Get and print the run\\nrun = pf.runs.get(name=\\\"\\\")\\nprint(run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 127, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate", "document_node": "{\"id_\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"056517ad-77d6-4567-bd42-784249e7099e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ac8e842a7b5768c58167cad9416d5c3a46f31c4ca4b60615181298880853c1d0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"95e1d717-5d19-478a-ba97-1d05ff659dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7606ca1a7a668df41015f56b251c28501a61771bf863fac263ae33419a544c8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"text\": \"Show run details\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run details with TABLE format.\\n\\n```bash\\npf run show --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run details with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nfrom tabulate import tabulate\", \"start_char_idx\": 2, \"end_char_idx\": 278, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9528494c-6fe6-435e-8311-638da383dc41\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6c987068-49f3-4b14-bc4c-96ad00ef3503\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fa59305ec872b3c2e75bbeead07642b3ad4c9d441c983dd1331b81518f4df3a2\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f68960fd-78ed-4eb5-9c21-41c88a20f97c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"49293e272e5907c1688626b39b858b564c40e0a463d3bbf18bc4ae7e5851ac17\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a7f71897-aad1-45f5-bc2b-9f3f30b22ab5\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"text\": \"Get and print the run-details\\nrun_details = pf.runs.get_details(name=\\\"\\\")\\nprint(tabulate(details.head(max_results), headers=\\\"keys\\\", tablefmt=\\\"grid\\\"))\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 216, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json", "document_node": "{\"id_\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"bafa7c22-c619-45f8-9c0d-e8fca3753d61\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7cf1e0bec2347094aba059e8ccaea3ab4d987ec96d413c8f38bc4c038be5a274\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9c64f257-4677-472c-8398-3412d05b959b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"64cc79d72a3e64367340533a5590284529a6654f8542131524d8c110453c3a20\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"text\": \"Show run metrics\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run show-metrics --name \\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nShow run metrics with `PFClient`\\n```python\\nfrom promptflow import PFClient\\nimport json\", \"start_char_idx\": 2, \"end_char_idx\": 267, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f36b0ba6-a935-419f-be60-64b86bfcd0af\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"1e406404-7711-4e48-9b6f-77e11a2ca881\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d78e36c5a046e72fc2f8de9aefcf9d3c15eb81eb1aa16989295b3b26f434f56\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::", "document_node": "{\"id_\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0acc4e77-5cef-41d4-8dd5-2d3ee287789a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"305909b84d1072067287befc0fbbab8cd1a5653d9336a909d32a9bacc21cf2d3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"826b1d52-f18a-4a93-a8ef-c46a23b65463\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"text\": \"Get and print the run-metrics\\nrun_details = pf.runs.get_metrics(name=\\\"\\\")\\nprint(json.dumps(metrics, indent=4))\\n```\\n:::\\n\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 125, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f1c9b212-965b-41d9-808f-a859cf2bcf64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f7b2bd2c6d767e2394c033cf46a8b2756409e7a2158e17b96e651c5c5ff13ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"be3ea111-9d97-4596-af99-16ccbba9e175\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"01536598b446057e813c171ad5ad572ea1e46268808c5994bfbad0c70b465c66\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"text\": \"Visualize a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nVisualize run in browser.\\n\\n```bash\\npf run visualize --name \\n```\\n\\nA browser will open and display run outputs.\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nVisualize run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 286, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"83ebe531-d05f-4a18-b981-b032188e1a91\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac7bfc33-7386-42b9-a5cb-120e026fc387\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44ff62cc5ec36103e3d33096a762ad1571d9781e53480d79e2fab0a201f7cc78\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::", "document_node": "{\"id_\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e0d47b6b-d1bb-4135-99c6-94e0587982d6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2dd6d3b52ab30d4dda87b658da7a20d31661a20e90afadbfd6ba9ee96ada3ab0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ddbe5f42-c96c-49df-b383-60f6f8dbd4d4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"text\": \"Visualize the run\\nclient.runs.visualize(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \\\"visualize\\\" button on the top-right to visualize the local runs.\\n\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 341, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8cd0973b-621c-4ac5-ab7b-b761e9464968\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3b8464057578b5ba3ccb4ef18e6269f22e0645221ea15c48138dba649196cbf3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"63d3d24f-4b3f-476e-9c89-cbfa5bef7b1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c53258e2459e0395fce1a3d8b8ab5494069cd553a1610e81e11d574b62ef64c3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"text\": \"List runs\\n\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nList runs with JSON format.\\n\\n```bash\\npf run list\\n```\\n\\n!img\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nList with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 215, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"689f1a61-021c-4d09-8f36-af664354d82a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5f7621ce-bfc1-42a9-8884-95ed5d572a29\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4977b21d3aa595dc6de32df7d2be035ca022ddd3c8d4f5d7c0f007e38fb6b4a3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::", "document_node": "{\"id_\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"62d58288-30a7-403a-ae78-e96ab797625a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8658b0ec41f3abc61402be75b54a6e1ae936ba8728c5ca85595757a37f92b1c8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6a507bb3-2548-4635-9e39-24aa770187d3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"text\": \"list runs\\nruns = pf.runs.list()\\nprint(runs)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n\\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 265, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a882a5b2-ae70-4e60-8dec-44ab6aa5de17\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9a99bfa43094dbfe48415d7cfa311835783debea8e004b3617c06d72e8a9f14e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8d6ce3b5-e89f-4abb-903e-f5135a1404ab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3e7763218e87b8e98e8ce7fcea62114e964dce94ae43b3ab086ae44bdf25149\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"text\": \"Update a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nGet run metrics with JSON format.\\n\\n```bash\\npf run update --name --set display_name=new_display_name\\n```\\n\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nUpdate run with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 269, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d622f6da-925e-4499-b2bc-e6c1b88a7764\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"945510d7-7ad6-42e4-8d9d-aef7c0885e63\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f9aff723d2cdeca9765a992fe2b6de451a5f351229fd25b526693ff3f8c36848\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::", "document_node": "{\"id_\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"12a0c48d-32ba-458c-b98b-5ce685fbecd1\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f180fb15fb20882c0f33f6f5bcf0d9c267d70b9f7fd04436d7be890c0ae9fbb1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2c4c1015-9a30-495d-86f6-c3e1cacc312f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"text\": \"Get and print the run-metrics\\nrun = pf.runs.update(name=\\\"\\\", display_name=\\\"new_display_name\\\")\\nprint(run)\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 118, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0e1f5935-4d6c-42a3-9b09-3da53cf5dbc6\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a226c721d83c0dc240f7149e90068679e1185971e0efc5cd3750d3688f7be6f4\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"62871c19-9eed-4813-9bf9-8f96053183ad\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"29d7b921e790fcb3d3818f90e44d985079bd5f647811ec44038788074e134d3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"text\": \"Archive a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nArchive the run so it won't show in run list results.\\n\\n```bash\\npf run archive --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nArchive with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 251, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a01b3d2-3028-4464-8113-24d35a37127c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27b731d9-f6a8-42fb-9216-b82cda8f384c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ee38553ec92fdf2d3d038330fe0d53e117bf6fe6ad960c080a0b1f243fd03377\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::", "document_node": "{\"id_\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"67df2602-4039-4fc6-b097-7d52f3ab80d3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e3105c8e1a55b304a67ffac4d9723179527619bd43eb7fb30ba9e8be0057b447\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6950e481-0220-4cb6-be94-1d26465cef50\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"text\": \"archive a run\\nclient.runs.archive(name=\\\"\\\")\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VSC\\n!img\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 110, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient", "document_node": "{\"id_\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"73b1be5c-105b-4991-a760-2cdc603ef913\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3515081b130b61184610302211a976ed86236d28529ea29de4e4062eeed2b6fb\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6d83afbe-74dd-4a50-a365-36c3ce93abb8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a125e23128ceb1580d249c9d5e3cf1f0412f426679e3a9f4f688698fbd36984\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"text\": \"Restore a run\\n\\n::::{tab-set}\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nRestore an archived run so it can show in run list results.\\n\\n```bash\\npf run restore --name \\n```\\n:::\\n\\n\\n:::{tab-item} SDK\\n:sync: SDK\\nRestore with `PFClient`\\n```python\\nfrom promptflow import PFClient\", \"start_char_idx\": 2, \"end_char_idx\": 257, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get a pf client to manage runs\npf = PFClient()", "document_node": "{\"id_\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4a6b2dca-a015-4f46-8e4c-8f420c172cfc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"bf9d8b0598a82f1c0512920b15ad8db56fb67a3d433c7973382a4e84aefa1150\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cfb3348-6344-49bc-abf2-8a83542f0d8a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f7f71a81ccf24e6398807bf345e9e8494005bdbc41d8d73b5d81d22b135b46c0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"text\": \"Get a pf client to manage runs\\npf = PFClient()\", \"start_char_idx\": 2, \"end_char_idx\": 48, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::", "document_node": "{\"id_\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"52013f35-f7b9-4ead-99a3-ce4a40a7b0a0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c9ff0a8fc8da582672ffd435dede081836c045e4c0bfad1bc35f00dd9ddd90b1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"02feac75-0cbc-45db-98c6-834b1410ac9e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"dad6a9ab417a27c64a73f697d9aec77cd247f3fae1d4e4df3dc8c70f0d6d8c8a\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"text\": \"restore a run\\nclient.runs.restore(name=\\\"\\\")\\n```\\n:::\\n::::\", \"start_char_idx\": 2, \"end_char_idx\": 57, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data.", "document_node": "{\"id_\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3f073cc8-dbd7-404a-b000-72bbff9558a2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b0fe45f7655286420820fe760ab00a37e2f5838b36fb118fc4ec5008b5f86060\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7bfde7e0-80dd-433c-800b-693425e89b05\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/manage-runs.md\", \"file_name\": \"manage-runs.md\", \"file_type\": \"text/markdown\", \"file_size\": 8120, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3244623c9aa25e4283f83ca13386ffffa0790f11fca06cc59d8b3db09f2f2bef\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"text\": \"Process image in flow\\nPromptFlow defines a contract to represent image data.\", \"start_char_idx\": 2, \"end_char_idx\": 78, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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.", "document_node": "{\"id_\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5efdffd0-715a-49b8-b862-8c06fd69756a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9037551182ef68ff8573f23d59d51ab0122c07bd8b67195a7927188e9cdfc942\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"2be32a2c-5f45-45ef-a98e-7e482769423d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"08398ef2e05292ca924e88b533c921d890c43ca0aeba0ea2dbf067029ce19aff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"text\": \"Data class\\n`promptflow.contracts.multimedia.Image`\\nImage 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.\", \"start_char_idx\": 2, \"end_char_idx\": 338, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image.", "document_node": "{\"id_\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"be5c5590-cc2c-471d-9a1a-9d6ba6654b4a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9cfbe119c907229fa7c21d195971a302e523c3d4fd165529faabcbe96bc04923\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3b30304b-9e4e-4dc7-918b-5b4729b20a80\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"8b55f118fbf23c270a59b559e7e7647f9e7049e694e5225060b7af9edb915095\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"text\": \"Data type in flow input\\nSet the type of flow input to `image` and promptflow will treat it as an image.\", \"start_char_idx\": 2, \"end_char_idx\": 105, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.", "document_node": "{\"id_\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"dbc9ce4b-d4c9-4821-9508-f9923f82ce76\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ae851217d3af4fca9c7ef102cf46a9c6e94d378388c1ce5ec771632962af0989\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"6e03338f-6811-4c7c-bd31-78b6eae128f9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f494bcb5743edbfb0626eefc6dc327ad91ebdc109984f4474039fcc49c52b9d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"text\": \"Reference image in prompt template\\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model.\", \"start_char_idx\": 2, \"end_char_idx\": 293, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario.", "document_node": "{\"id_\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"25990bbe-88b7-404e-b27b-dba038a55cab\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c110c9ce51caed1fd070c097b462340c73e276069cb4bf96a739d73cba30a06e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a33946f5-086b-43fb-8a08-30b9eb1b1e70\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6bca86b43c44221d224d7755d03b36f0b4117a1f73bda5a68e48f6fa2462750d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"text\": \"Serialization/Deserialization\\nPromptflow uses a special dict to represent image.\\n`{\\\"data:image/;\\\": \\\"\\\"}`\\n\\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\\n- `` is the image serialized representation, there are 3 supported types:\\n\\n - url\\n\\n It can point to a public accessable web url. E.g.\\n\\n {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\\\"}\\n - base64\\n\\n It can be the base64 encoding of the image. E.g.\\n\\n {\\\"data:image/png;base64\\\": \\\"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\\\"}\\n\\n - path\\n\\n 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.\\n\\n {\\\"data:image/png;path\\\": \\\"./my-image.png\\\"}\\n\\nPlease note that `path` representation is not supported in Deployment scenario.\", \"start_char_idx\": 2, \"end_char_idx\": 1496, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```", "document_node": "{\"id_\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"19d77c76-c58e-4192-90d8-c49cb217b41c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"92124ab99bd3cf499149ae86dd3f01b6d954639f457778cad90613e5049ac45e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4fbffe55-17f7-43eb-8eb6-052eb8ede244\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c5ffd68ada8e90bbe5b4f94ecd6ee940adf00fe67e44856e8c7e6b3f50bf09b3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"text\": \"Batch Input data\\nBatch input data containing image can be of 2 formats:\\n1. 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.\\n ```json\\n {\\\"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\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;url\\\": \\\"https://developer.microsoft.com/_devcom/images/404.png\\\"}}\\n ```\\n2. 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:\\n ```\\n BatchInputFolder\\n |----input.jsonl\\n |----image1.png\\n |----image2.png\\n ```\\n Content of `input.jsonl`\\n ```json\\n {\\\"question\\\": \\\"How many colors are there in the image?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image1.png\\\"}}\\n {\\\"question\\\": \\\"What's this image about?\\\", \\\"input_image\\\": {\\\"data:image/png;path\\\": \\\"image2.png\\\"}}\\n ```\", \"start_char_idx\": 2, \"end_char_idx\": 1318, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.", "document_node": "{\"id_\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"13b2e87c-864e-48d7-a298-aa0405987f0e\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"79570951aa402f8b5f4e3c3b8c54c819fcb929b1a4d6de04a5f0a9e9b9d305c5\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"016738b7-5aee-486d-82d0-e8d21a9a83d9\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/process-image-in-flow.md\", \"file_name\": \"process-image-in-flow.md\", \"file_type\": \"text/markdown\", \"file_size\": 3873, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"43ec318cd91b79443347a5d0b8d4eaaeba0f5b1930672571de1677099ad84fa1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"text\": \"Quick Start\\n\\nThis guide will walk you through the fist step using of prompt flow code-first experience.\\n\\n**Prerequisite** - To make the most of this tutorial, you'll need:\\n\\n- Know how to program with Python :)\\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\\n\\n\\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\\n- Setup your python environment to run prompt flow\\n- Clone a sample flow & understand what's a flow\\n- Understand how to edit the flow using visual editor or yaml\\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension.\", \"start_char_idx\": 2, \"end_char_idx\": 623, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash", "document_node": "{\"id_\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cccf3a8-00b2-4eea-925d-a6d165906fb2\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"587ff0eab41d0c313506a1b48bba59f016d271767a7706df438d3b94b95d70f1\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9a834be9-abaa-480e-982a-bea8c7a5c2cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2df5e97cfd86bd2a3dc226a85a87c18df9e1ee5a497a5295e32b13e1a9862267\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"text\": \"Set up your dev environment\\n\\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\\n```bash\\nconda create --name pf python=3.9\\nconda activate pf\\n```\\n\\n2. Install `promptflow` and `promptflow-tools`.\\n```sh\\npip install promptflow promptflow-tools\\n```\\n\\n3. Check the installation.\\n```bash\", \"start_char_idx\": 2, \"end_char_idx\": 457, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```", "document_node": "{\"id_\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"38042954-c5f8-49e2-ad7a-8dd102cb9e4b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1c85e37e9cb465346ff4d30d688adc584079228796b48af10d2c71ceb2335616\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"26154288-f809-403f-b466-a0e18d9d83ee\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b58d0298d561c2896f05002fb98c88d876b23b3e4ce8ce524f8b94cb7fa07d01\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"text\": \"should print promptflow version, e.g. \\\"0.1.0b3\\\"\\npf -v\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 59, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.", "document_node": "{\"id_\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"2ba34ea4-ae4b-4056-b39f-5912c5a0fa64\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3a4f168922683539a819e5ea2cd78f563c61381d82a343207632856d7d161254\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"3f49db3b-a7bc-448c-87eb-355dd6a528a3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"086b2749d09e86ef0ede9918e6234ede5591d82efb8cf8b28fff8854833781e5\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"text\": \"Understand what's a flow\\n\\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details.\", \"start_char_idx\": 2, \"end_char_idx\": 224, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```", "document_node": "{\"id_\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a05adf23-8e8c-45aa-b2af-53428b3c4ab3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"eb849308243c212f582c607ade0182cb365a92c8d404b5e5fb594118d2c07357\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"072fa0ee-18d6-4fd2-a6fa-1a1fbb3875ba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"386f5cae95b927913e52669c2d2d154509525b595a16b9990b93bfbfcd936a97\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"text\": \"Get the flow sample\\n\\nClone the sample repo and check flows in folder examples/flows.\\n\\n```bash\\ngit clone https://github.com/microsoft/promptflow.git\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 153, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```", "document_node": "{\"id_\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"79a0a064-1fcf-426a-8548-0cbbbe034e7c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"44b92b2fd3a018be8e3053359e32a4423d9b6474f12db760ac37fe43281bbb32\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"269f0ce8-2aee-4cdb-9833-4cb62b49b849\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"90dc4149b2716f6dc695cb67f549888eff755ea656f06d37745f20d13a2ee076\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"text\": \"Understand flow directory\\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\\n\\n```bash\\ncd promptflow/examples/flows/standard/web-classification\\n```\\n\\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\\n- **requirements.txt**: Python package dependencies for this flow.\\n\\n\\n!flow_dir\\n\\nIn order to run this specific flow, you need to install its requirements first.\\n\\n```sh\\npip install -r requirements.txt\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 946, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section.", "document_node": "{\"id_\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e7c432c7-346e-4c79-9d66-4944eaab2398\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"585f3bbe83645c654d93216d5a9b001b56b9ef008cf9693379ade54887ec1a42\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9cb45658-6da0-4d16-b5db-257768302152\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"ce12a2816bb578f60e52f99d0f49377b38f8357eadb13e5bb83ba9b5c0e4b7b0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"text\": \"Understand the flow yaml\\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\\n\\n!flow_dag\\n\\nThis graph is rendered by VS Code extension which will be introduced in the next section.\", \"start_char_idx\": 2, \"end_char_idx\": 274, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode", "document_node": "{\"id_\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"5d15c1f0-b882-4e0f-a58e-b1f1e5f9e228\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"81e60ad7a846d99edaec0186774aa9ebb0110cb857c56d2328868b7e0fa46711\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0449bea9-8dad-4bc1-ac78-e8a3a965012b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9d3000ec304a9cbad589be5def8e6724a62450d6ab0f11f903d372483e69ccd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"text\": \"Using VS Code Extension to visualize the flow\\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\\n\\n1. Prerequisites for VS Code extension.\\n - Install latest stable version of VS Code\\n - Install VS Code Python extension\\n\\n2. Install Prompt flow for VS Code extension\\n\\n3. Select python interpreter\\n\\n !vscode\\n !vscode\\n\\n\\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\\n !vscode\", \"start_char_idx\": 2, \"end_char_idx\": 497, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Develop and test your flow", "document_node": "{\"id_\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"720071dc-66cc-4ed4-9b59-173a870d30ff\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"714af737aa81a554f0df7e22fd1b79dcdd62a3fbdd515c290cad89305d189339\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"7c82cf02-9c2c-414b-8e4f-2d1d788ed743\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"345c242d7acbe54b64e77b4e883406259737f74956effcf8f654c7126cd5996b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"text\": \"Develop and test your flow\", \"start_char_idx\": 2, \"end_char_idx\": 28, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow.", "document_node": "{\"id_\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"488319e9-bfcd-4afc-a6dc-d9dc568d8222\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4280e9afda0f6e201ad8aa74bea5818f07bfee49457a332e90c7775a5b169aea\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ac2cdcf8-610a-40dc-b268-cc949a0d5f66\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"fad902960c4d5cb4207e33abea570d1fc70b3630bb49a4d31406340a9ac52732\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"text\": \"How to edit the flow\\n\\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\\ninputs:\\n url:\\n type: string\\n # change the default value of input url here\\n default: https://play.google.com/store/apps/details?id=com.twitter.android\\n...\\n```\\nSee more details of this topic in Develop a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 532, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection", "document_node": "{\"id_\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"aba5bfb1-05ae-468c-be62-0a1a07c9d628\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4304344b05c441a6eb462f8c791c8d9a04408b2ff3ebeb03674bafdc081a41e3\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5fddd3dc-eea0-4824-a0c5-9d2baad76f1d\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f55c6ed87c5a77d7093fc043eee09a3fa2bb5c4d3c41aa28713344260787497b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"text\": \"Create necessary connections\\n\\n:::{note}\\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\\n:::\\n\\n\\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\\n\\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\\n\\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nFirstly we need a connection yaml file `connection.yaml`:\\n\\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: azure_open_ai\\napi_key: \\napi_base: \\napi_type: azure\\napi_version: \\n```\\n\\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\\nname: open_ai_connection\\ntype: open_ai\\napi_key: \\\"\\\"\\norganization: \\\"\\\" # optional\\n```\\nThen we can use CLI command to create the connection.\\n\\n```sh\\npf connection create -f connection.yaml\\n```\\n\\nMore command details can be found in CLI reference.\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nIn SDK, connections can be created and managed with `PFClient`.\\n\\n```python\\nfrom promptflow import PFClient\\nfrom promptflow.entities import AzureOpenAIConnection\", \"start_char_idx\": 2, \"end_char_idx\": 1802, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections.", "document_node": "{\"id_\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c529519b-67a4-4ca2-82d6-88e7699c8200\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7ed7487a25062f53a7b930269186ea7f0954012d2027cad99b2715db455927b9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"060b6522-e3b5-495c-859a-8f26231fb7c4\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b44752cb470560ff7cdc5ad7f0d626c4b7ed2eb734c4f5b40471f9b6cf029730\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"text\": \"PFClient can help manage your runs and connections.\\npf = PFClient()\\n\\ntry:\\n conn_name = \\\"open_ai_connection\\\"\\n conn = pf.connections.get(name=conn_name)\\n print(\\\"using existing connection\\\")\\nexcept:\\n connection = AzureOpenAIConnection(\\n name=conn_name,\\n api_key=\\\"\\\",\\n api_base=\\\"\\\",\\n api_type=\\\"azure\\\",\\n api_version=\\\"\\\",\\n )\\n\\n # use this if you have an existing OpenAI account\\n # from promptflow.entities import OpenAIConnection\\n # connection = OpenAIConnection(\\n # name=conn_name,\\n # api_key=\\\"\\\",\\n # )\\n\\n conn = pf.connections.create_or_update(connection)\\n print(\\\"successfully created connection\\\")\\n\\nprint(conn)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\n\\n\\n1. Click the promptflow icon to enter promptflow control panel\\n\\n !vsc_add_connection\\n\\n2. Create your connection.\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n !vsc_add_connection\\n\\n\\n:::\\n\\n::::\\n\\nLearn more on more actions like delete connection in: Manage connections.\", \"start_char_idx\": 2, \"end_char_idx\": 1030, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name", "document_node": "{\"id_\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"6e2090d9-29f8-4fce-90c8-b577f114642b\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6d5a26e33893b1d820d9201b77c301375b1bac6e1020962824c2eab192622768\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f50a0c68-fc84-4da6-897b-749bda44d2e0\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9532871979b6df968ab4e650decceaaf6bdaff5d2d609c9d41e677f4c0883583\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"text\": \"Test the flow\\n\\n:::{admonition} Note\\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\\n:::\\n\\n\\nAssuming you are in working directory `promptflow/examples/flows/standard/`\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nChange the default input to the value you want to test.\\n\\n!q_0\\n\\n```sh\\npf flow test --flow web-classification # \\\"web-classification\\\" is the directory name\\n```\\n\\n!flow-test-output-cli\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\nThe return value of `test` function is the flow/node outputs.\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient()\\n\\nflow_path = \\\"web-classification\\\" # \\\"web-classification\\\" is the directory name\", \"start_char_idx\": 2, \"end_char_idx\": 793, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")", "document_node": "{\"id_\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"00d12aa2-2fba-4094-ba89-2b5100553cbf\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2eb38f79e9511a30a686a54c0c9328d8f27b6533f88da23af285578f841f825c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"922acc06-465a-4510-9b01-32a62a47b9ac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7c6119aacd6cbf6b6811d68a0b56556cf9af5ccaa0b602d365d75644a3f9eef1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"text\": \"Test flow\\nflow_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\", \\\"answer\\\": \\\"Channel\\\", \\\"evidence\\\": \\\"Url\\\"} # The inputs of the flow.\\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\\nprint(f\\\"Flow outputs: {flow_result}\\\")\", \"start_char_idx\": 2, \"end_char_idx\": 243, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow.", "document_node": "{\"id_\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c8481bc3-2fa6-4f9e-bbcf-50426bc810c9\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2f184b383bba7eaa575f03d802ddda93cb93c77c0c9aa1a1b18fc95da8c0b85c\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d8cd8ccb-9cd6-4a8e-b012-8b66e9b7aeb3\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2d094684fdd7637f15b36a91cbe336fbe7f891fbace80cdb14fcd382aa49eb1f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"text\": \"Test node in the flow\\nnode_name = \\\"fetch_text_content_from_url\\\" # The node name in the flow.\\nnode_inputs = {\\\"url\\\": \\\"https://www.youtube.com/watch?v=o5ZQyXaAv1g\\\"} # The inputs of the node.\\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\\nprint(f\\\"Node outputs: {node_result}\\\")\\n```\\n\\n!Flow test outputs\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n\\nUse the code lens action on the top of the yaml editor to trigger flow test\\n!dag_yaml_flow_test\\n\\n\\nClick the run flow button on the top of the visual editor to trigger flow test.\\n!visual_editor_flow_test\\n:::\\n\\n::::\\n\\nSee more details of this topic in Initialize and test a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 666, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.", "document_node": "{\"id_\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"7cd6ec34-2ff3-4ef6-a334-5325a792d6be\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9f922b16e03e9c87176794882ed1ecdce02c8480f87787e537137efa790a4d7b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b178c0f1-e117-4d3e-a6d8-8250ee3f8cba\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"e58c450483505c1d0d1edcf9b14e11acb44ca8c340c792d8cf0745a99c62ecc8\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"text\": \"Next steps\\n\\nLearn more on how to:\\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\\n- Deploy a flow: how to deploy the flow as a web app.\\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\\n\\nAnd you can also check our examples, especially:\\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics.\", \"start_char_idx\": 2, \"end_char_idx\": 1011, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow.", "document_node": "{\"id_\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"30c31860-92f8-47c4-8143-ed8a60bef754\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"a6456b9cffe36ddc31ab56d1934541df995350acf57169caef45954e5432ef45\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9791985c-36af-4724-a26e-7c59308fe630\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/quick-start.md\", \"file_name\": \"quick-start.md\", \"file_type\": \"text/markdown\", \"file_size\": 12243, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"68b46710a11a3507fdc3719db72295afdf36e3049728b74a063b1d0cc2f5d2ff\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"text\": \"Use column mapping\\n\\nIn this document, we will introduce how to map inputs with column mapping when running a flow.\", \"start_char_idx\": 2, \"end_char_idx\": 116, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column.", "document_node": "{\"id_\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f7f2a950-7877-4434-9ad9-91c026212720\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"7463dd8b40dd4febe72041037b50febcc30e9f037aa9038b0930a4ce8aed2b8a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f9b0f1c8-f547-4dc1-b42a-9b18d05d6bab\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"60fc35cd6ecdf7be35c81bad69905fb4c9e096c482e6f7adad6e49e938448c3b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"text\": \"Column mapping introduction\\n\\nColumn mapping is a mapping from flow input name to specified values.\\nIf specified, the flow will be executed with provided value for specified inputs.\\nThe following types of values in column mapping are supported:\\n\\n- `${data.}` to reference from your test dataset.\\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\\n- `STATIC_VALUE` to create static value for all lines for specified column.\", \"start_char_idx\": 2, \"end_char_idx\": 504, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow", "document_node": "{\"id_\": \"54218434-a846-4601-b725-da39ad450bac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"3b22908e-2696-4ca0-ab38-15c436581212\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4a65e49af872870820c0aa44888d4bec1d26b74f685c8f8f6b0e82e567dcaa2e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"004b93b9-ace5-4a11-a716-9750f5de45b1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"b59c85a379a702b9a2a803a4ca0c663aa8bc2d8673ea0d7eb3c2c6ce3f9c8789\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"text\": \"Flow inputs override priority\\n\\nFlow input values are overridden according to the following priority:\\n\\n\\\"specified in column mapping\\\" > \\\"default value\\\" > \\\"same name column in provided data\\\".\\n\\nFor example, if we have a flow with following inputs:\\n\\n```yaml\\ninputs:\\n input1:\\n type: string\\n default: \\\"default_val1\\\"\\n input2:\\n type: string\\n default: \\\"default_val2\\\"\\n input3:\\n type: string\\n input4:\\n type: string\\n...\\n```\\n\\nAnd the flow will return each inputs in outputs.\\n\\nWith the following data\\n\\n```json\\n{\\\"input3\\\": \\\"val3_in_data\\\", \\\"input4\\\": \\\"val4_in_data\\\"}\\n```\\n\\nAnd use the following YAML to run\\n\\n```yaml\\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\\nflow: path/to/flow\", \"start_char_idx\": 2, \"end_char_idx\": 718, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data", "document_node": "{\"id_\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85ecd312-c7aa-48ca-89cb-4d16ac411b2d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"924fbc0961d3d7d9de76a32f571c6ff05573670311e7c52c2288ea2aa20c43da\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"54218434-a846-4601-b725-da39ad450bac\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f99675f03a17a70c3acfcffb41c7477b49d953e8e72bc244fc9956dc256a9e96\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"text\": \"my_flow has default value val2 for key2\\ndata: path/to/data\", \"start_char_idx\": 2, \"end_char_idx\": 60, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data.", "document_node": "{\"id_\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e74459fb-15d7-4a3d-ae93-101437c2bd75\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"698d6a2dc2865dae75ed798ff334ae53e59410e15e656c44e2cedc8fd117bb6b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"5a97badc-7345-4e94-8505-ea440a97933e\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"62c63a8129a14a0a32cab769023bc69b4cb47a45c6a13608f60f8df84f7ab770\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"text\": \"my_data has column key3 with value val3\\ncolumn_mapping:\\n input1: \\\"val1_in_column_mapping\\\"\\n input3: ${data.input3}\\n```\\n\\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\\n\\n!column_mapping_details\\n\\n- Input \\\"input1\\\" has value \\\"val1_in_column_mapping\\\" since it's specified as constance in `column_mapping`.\\n- Input \\\"input2\\\" has value \\\"default_val2\\\" since it used default value in flow dag.\\n- Input \\\"input3\\\" has value \\\"val3_in_data\\\" since it's specified as data reference in `column_mapping`.\\n- Input \\\"input4\\\" has value \\\"val4_in_data\\\" since it has same name column in provided data.\", \"start_char_idx\": 2, \"end_char_idx\": 657, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.", "document_node": "{\"id_\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"0745af7e-ec63-49a3-8913-9ce62b2de223\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"27e034e72d909f547920ecb5bfea736f1ab1e439d826daa7d913ef75116ce89f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"4e11f7f9-efb5-4382-b6c0-ee72853c6dc8\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/run-and-evaluate-a-flow/use-column-mapping.md\", \"file_name\": \"use-column-mapping.md\", \"file_type\": \"text/markdown\", \"file_size\": 2198, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"4649df83054c6038472f91f19309efddb074cf8c5a3fe167f809a14a02953f83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"text\": \"Set global configs\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\\n\\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli.\", \"start_char_idx\": 2, \"end_char_idx\": 541, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```", "document_node": "{\"id_\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c304b195-516b-47e0-900a-fbad4496fde3\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"88f72ac96bfaa0b271618b9c8f66bcc2de5d37e2a9e6d26e26bcc54921321ebd\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"620a84a5-8eb2-48b4-9f06-6c641eb3e54a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"0f4e09c31cd269e82dbb115ca28bbf3ea65e09e22acad1909cd6e42fb024b310\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"text\": \"Set config\\n```shell\\npf config set =\\n```\\nFor example:\\n```shell\\npf config set connection.provider=\\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 200, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```", "document_node": "{\"id_\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"a73d8903-c78a-4ef8-8591-c5fe90893d80\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"264d76e266c35e6a139d87b304d20aaf5393fe43b13ece323df3ff74b235e613\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"47eb76af-2cdd-4899-8c0d-9836d1b8c42a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"736625bb649fd9e760d77ac557171a6e7f9a4b2aecfec38e75fbb5753abf6f32\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"text\": \"Show config\\nThe following command will get all configs and show them as json format:\\n```shell\\npf config show\\n```\\nAfter running the above config set command, show command will return the following result:\\n```json\\n{\\n \\\"connection\\\": {\\n \\\"provider\\\": \\\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\\"\\n }\\n}\\n```\", \"start_char_idx\": 2, \"end_char_idx\": 358, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values.", "document_node": "{\"id_\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b56e2759-71a4-4872-aac3-59ee3a94a1f5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1761fcf18f56ea37a32fff9d05bc05935c4d26f821644ab355085b65b7d1a304\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"f930e2d6-5960-4242-b3cf-6cf6c135233f\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"1331f84a615b81f833194550f326fe8e119518c7e888e43b494234911159374f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"text\": \"Supported configs\\nThe connection provider, default to \\\"local\\\". There are 3 possible provider values.\", \"start_char_idx\": 2, \"end_char_idx\": 102, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.", "document_node": "{\"id_\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8e66b553-7359-4b97-afdc-8f38395dc946\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"09bfdea661db0c1bc689c1372efa2a0820d2f05cbcaebd5f56fb3e0542f42848\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"9d08ab6e-58cd-4e1c-bbde-9cf2986c10e1\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2519bb547f7412dde306d42c10067e58392cba00faff3ac18223a4ae355054d6\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"text\": \"local\\nSet connection provider to local with `connection.provider=local`.\\n\\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections.\", \"start_char_idx\": 2, \"end_char_idx\": 252, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::", "document_node": "{\"id_\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"07f8fe3d-7333-4508-a442-6d98e99eef0d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"91bd5a95942ac400dca084af0a6320249f0b2e643d08b786e6608b413a891d7d\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"b315e7e3-878d-4de2-be62-14c9f2aca9cc\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d79ddef66fc2b4ccb53bed5f1928efbc225ff135231c2a74a4f707c6e2a61cd0\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"text\": \"full azure machine learning workspace resource id\\nSet connection provider to a specific workspace with:\\n```\\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\\n```\\n\\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\\n\\n:::{note}\\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\\n:::\", \"start_char_idx\": 2, \"end_char_idx\": 701, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.", "document_node": "{\"id_\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"4ca93927-7b13-4533-a448-2c9898d0a1c7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d2ac101a7dad86028f9b2b6cc6cb864cf7a91da7f23df582bc7a081651a09b19\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"20e781f7-ee2e-4378-ad50-520c82fcf443\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"459de3c1e4075b3ebfdb3e9ad1fd792e3d73d624d42d268d782d2e3efd23ec33\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"text\": \"azureml\\nIn addition to the full resource id, you can designate the connection provider as \\\"azureml\\\" with `connection.provider=azureml`. In this case,\\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\\n\\nThe expected format of the config file is as follows:\\n```json\\n{\\n \\\"workspace_name\\\": \\\"\\\",\\n \\\"resource_group\\\": \\\"\\\",\\n \\\"subscription_id\\\": \\\"\\\"\\n}\\n\\n```\\n\\n> \\ud83d\\udca1 Tips\\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more.\", \"start_char_idx\": 2, \"end_char_idx\": 763, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first.", "document_node": "{\"id_\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"f4b19098-b649-49fb-ba3a-256c50177102\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f1d3fdba7aff41e34517c387405f43a643cc9bdc273d4608b5b84dabc5b8561e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c808b311-3508-4178-bfa9-4232c3c46a7a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/set-global-configs.md\", \"file_name\": \"set-global-configs.md\", \"file_type\": \"text/markdown\", \"file_size\": 3407, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"6606e91cb942c46d2d6b346c7ff2ce4f365f336c6b0545a3447d627cdfd1db64\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"text\": \"Tune prompts using variants\\n\\n:::{admonition} Experimental feature\\nThis is an experimental feature, and may change at any time. Learn more.\\n:::\\n\\nTo better understand this part, please read Quick start and Run and evaluate a flow first.\", \"start_char_idx\": 2, \"end_char_idx\": 236, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence.", "document_node": "{\"id_\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"596d09b8-71b6-4d61-8033-f700c9e6e166\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"f86c56fcebb73fc409192845f5a32aeb1bdc75a71e12db269ab09c95f37353ce\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"a9b5af62-0f92-4b56-9de8-5b457b640d2b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"24cbb1237233c16e18a61d2a41444bf728cb8c99d6614289af476d80183e73a7\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"text\": \"What is variant and why should we care\\n\\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\\u2019s accuracy, diversity, or coherence.\", \"start_char_idx\": 2, \"end_char_idx\": 400, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\"", "document_node": "{\"id_\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"042639b8-edf6-4943-b574-68f37cb821e5\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"3891ba9e1032a54312c877719e8bc6185815a78c2077ee309de42674e31602f8\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"860eba23-d3dd-456b-972c-e46f19709474\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c0a5ae16845fddfa0bf057908e455471a6e8d52d0093a1ffd72d60b9d7f6c5de\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"text\": \"Create a run with different variant node\\n\\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\\n\\n\\n```yaml\\n...\\nnodes:\\n- name: summarize_text_content\\n use_variants: true\\n...\\nnode_variants:\\n summarize_text_content:\\n default_variant_id: variant_0\\n variants:\\n variant_0:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '128'\\n temperature: '0.2'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n variant_1:\\n node:\\n type: llm\\n source:\\n type: code\\n path: summarize_text_content__variant_1.jinja2\\n inputs:\\n deployment_name: text-davinci-003\\n max_tokens: '256'\\n temperature: '0.3'\\n text: ${fetch_text_content_from_url.output}\\n provider: AzureOpenAI\\n connection: open_ai_connection\\n api: completion\\n module: promptflow.tools.aoai\\n```\\n\\nYou can check the whole flow definition in flow.dag.yaml.\\n\\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \\nAssuming you are in working directory `/examples/flows/standard`\\n\\n\\n::::{tab-set}\\n\\n:::{tab-item} CLI\\n:sync: CLI\\n\\nNote we pass `--variant` to specify which variant of the node should be running.\\n\\n```sh\\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\\n```\\n\\n:::\\n\\n:::{tab-item} SDK\\n:sync: SDK\\n\\n```python\\nfrom promptflow import PFClient\\n\\npf = PFClient() # get a promptflow client\\nflow = \\\"web-classification\\\"\\ndata= \\\"web-classification/data.jsonl\\\"\", \"start_char_idx\": 2, \"end_char_idx\": 2080, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.", "document_node": "{\"id_\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"8551fee8-9698-4a4e-a6c2-68ad0c5ad168\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"c4b1feb415aba95a00177594f96a7c35009b9cc3a06174dfdc0557050e30fdb0\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ede8d287-1444-41fc-8458-78ac3ef016b7\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"9571cf93f40f17e7d8c98bdb3905912e227dac4d1b4c6bff27847e02c61525e3\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"node_type\": \"1\", \"metadata\": {}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"text\": \"use the variant1 of the summarize_text_content node.\\nvariant_run = pf.run(\\n flow=flow,\\n data=data,\\n variant=\\\"${summarize_text_content.variant_1}\\\", # use variant 1.\\n column_mapping={\\\"url\\\": \\\"${data.url}\\\"},\\n)\\n\\npf.stream(variant_run)\\n```\\n:::\\n\\n:::{tab-item} VS Code Extension\\n:sync: VS Code Extension\\n!img\\n!img\\n:::\\n\\n::::\\n\\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run.\", \"start_char_idx\": 2, \"end_char_idx\": 465, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} -{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI", "document_node": "{\"id_\": \"87f644d6-15b6-42eb-a771-e4e78c72d7ac\", \"embedding\": null, \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"98e9445a-c154-4bc3-9647-d54e3459349d\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"2fbfc42e24e9a1378f4fafdbd1334335ff983a743a84920e31777f80cf4f2921\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"c1d0ea43-6480-4d07-a82f-f8b7722c494b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"/mnt/azureml/cr/j/14ea0daf2baa4e8d81ac0b6fbc565c03/cap/data-capability/wd/INPUT_documents_folder/tune-prompts-with-variants.md\", \"file_name\": \"tune-prompts-with-variants.md\", \"file_type\": \"text/markdown\", \"file_size\": 3977, \"creation_date\": \"2024-01-18\", \"last_modified_date\": \"2024-01-18\", \"last_accessed_date\": \"2024-01-18\"}, \"hash\": \"d93a8ff8a1646d589f7894f8e26f0f6362c8b2cdbd938e4c5b80e34814d9328c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"88462da1d7f3de0077f97b7913e57cf48054b7796f6dd947a4cc37faec0877e0\", \"text\": \"Next steps\\n\\nLearn more about:\\n- Run and evaluate a flow\\n- Deploy a flow\\n- Prompt flow in Azure AI\", \"start_char_idx\": 2, \"end_char_idx\": 99, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} \ No newline at end of file diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 50f8cff40ea..c634522b9a6 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,6 +1,7 @@ import json import os from datetime import datetime +from pathlib import Path import configargparse from azure.ai.ml import Input, MLClient, dsl, load_component @@ -10,14 +11,14 @@ from promptflow._utils.logger_utils import get_logger from promptflow.entities import Run -CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) +CONFIG_FILE = (Path(__file__).parents[1] / "config.ini").resolve() -UTILS_PATH = os.path.abspath(os.path.join(os.getcwd(), "gen_test_data", "utils")) +UTILS_PATH = os.path.abspath(Path(__file__).parents[0] / "utils") if UTILS_PATH not in os.sys.path: os.sys.path.insert(0, UTILS_PATH) -from common import clean_data_and_save, split_document # noqa: E402 -from components import clean_test_data_set, document_split # noqa: E402 +from common import clean_data_and_save, split_document, count_non_blank_lines # noqa: E402 +from components import clean_data_and_save_component, split_document_component # noqa: E402 from constants import CONNECTIONS_TEMPLATE, TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") @@ -30,7 +31,7 @@ def batch_run_flow( flow_batch_run_size: int, connection_name: str = "azure_open_ai_connection", ): - logger.info("Start to submit the batch run.") + logger.info("Step 2: Start to batch run generate test data flow.") base_run = pf.run( flow=flow_folder, data=flow_input_data, @@ -95,8 +96,9 @@ def gen_test_data_pipeline( data = ( data_input if should_skip_doc_split - else document_split(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output + else split_document_component(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output ) + flow_node = load_component(flow_yml_path)( data=data, text_chunk="${data.text_chunk}", @@ -110,7 +112,7 @@ def gen_test_data_pipeline( flow_node.max_concurrency_per_instance = max_concurrency_per_instance flow_node.set_resources(instance_count=instance_count) - clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) + clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs) def run_local( @@ -123,6 +125,7 @@ def run_local( output_folder, should_skip_split, ): + logger.info("Start to generate test data at local.") text_chunks_path = document_nodes_file inner_folder = os.path.join(output_folder, datetime.now().strftime("%b-%d-%Y-%H-%M-%S")) if not os.path.isdir(inner_folder): @@ -167,6 +170,7 @@ def run_cloud( prs_max_concurrency_per_instance, should_skip_split, ): + logger.info("Start to generate test data at cloud.") ml_client = get_ml_client(subscription_id, resource_group, workspace_name) if should_skip_split: @@ -194,7 +198,7 @@ def run_cloud( if __name__ == "__main__": - if os.path.isfile(CONFIG_FILE): + if Path(CONFIG_FILE).is_file(): parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) else: raise Exception( @@ -231,9 +235,11 @@ def run_cloud( args = parser.parse_args() should_skip_split_documents = False - if args.document_nodes_file and os.path.isfile(args.document_nodes_file): + if args.document_nodes_file and Path(args.document_nodes_file).is_file(): + logger.info("Received document node input file, skip step 1 'split documents to document nodes'.") + logger.info(f"Collect {count_non_blank_lines(args.document_nodes_file)} document nodes from document node input file.") should_skip_split_documents = True - elif not args.documents_folder or not os.path.isdir(args.documents_folder): + elif not args.documents_folder or not Path(args.documents_folder).is_dir(): parser.error("Either 'documents_folder' or 'document_nodes_file' should be specified correctly.") if args.cloud: diff --git a/examples/gen_test_data/gen_test_data/utils/common.py b/examples/gen_test_data/gen_test_data/utils/common.py index 00b9552c79f..bb030c7896a 100644 --- a/examples/gen_test_data/gen_test_data/utils/common.py +++ b/examples/gen_test_data/gen_test_data/utils/common.py @@ -1,5 +1,4 @@ import json -import os import typing as t from pathlib import Path @@ -19,7 +18,7 @@ def split_document(chunk_size, documents_folder, document_node_output): logger = get_logger("doc.split") - logger.info("Start to split the documents.") + logger.info("Step 1: Split documents to document nodes.") documents = SimpleDirectoryReader( documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" ).load_data() @@ -29,19 +28,21 @@ def split_document(chunk_size, documents_folder, document_node_output): documents = t.cast(t.List[LlamaindexDocument], documents) document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - with open(os.path.join(document_node_output, "document_nodes.jsonl"), "wt") as text_file: + logger.info(f"End to split the documents and generate {len(document_nodes)} document nodes.") + document_nodes_output_path = document_node_output / Path("document_nodes.jsonl") + with open(document_nodes_output_path, "wt") as text_file: for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) - logger.info(f"End to split the documents and generate {len(document_nodes)} document nodes.") + logger.info(f"Saved document nodes to {document_nodes_output_path}.") return str((Path(document_node_output) / "document_nodes.jsonl")) def clean_data_and_save(test_data_set: list, test_data_output_path: str): logger = get_logger("data.clean") - logger.info(f"Collected {len(test_data_set)} test data after the batch run. " - f"Initiating data cleaning process.") + logger.info("Step 3: Clean invalid test data.") + logger.info(f"Collected {len(test_data_set)} test data after the batch run.") cleaned_data = [] for test_data in test_data_set: @@ -57,3 +58,11 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): logger.info( f"Collected {len(cleaned_data)} valid test data. " f"The cleaned data has been saved to {test_data_output_path}.") + + +def count_non_blank_lines(file_path): + with open(file_path, 'r') as file: + lines = file.readlines() + + non_blank_lines = len([line for line in lines if line.strip()]) + return non_blank_lines \ No newline at end of file diff --git a/examples/gen_test_data/gen_test_data/utils/components.py b/examples/gen_test_data/gen_test_data/utils/components.py index 253173655ab..cdd0c04df9d 100644 --- a/examples/gen_test_data/gen_test_data/utils/components.py +++ b/examples/gen_test_data/gen_test_data/utils/components.py @@ -1,5 +1,4 @@ import json -import os from pathlib import Path from mldesigner import Input, Output, command_component @@ -8,16 +7,15 @@ @command_component( - name="document_split", - version="1.0.4", + name="split_document_component", display_name="split documents", - description="Split documents into chunks.", + description="Split documents into document nodes.", environment=ENVIRONMENT_DICT_FIXED_VERSION, ) -def document_split( +def split_document_component( documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") ) -> str: - """Split documents into chunks. + """Split documents into document nodes. Args: documents_folder: The folder containing documents to be split. @@ -31,13 +29,12 @@ def document_split( @command_component( - name="clean_test_data_set", - version="1.0.4", + name="clean_data_and_save_component", display_name="clean dataset", description="Clean test data set to remove empty lines.", environment=ENVIRONMENT_DICT_FIXED_VERSION, ) -def clean_test_data_set( +def clean_data_and_save_component( test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") ) -> str: test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" @@ -45,7 +42,7 @@ def clean_test_data_set( with open(test_data_set_path, "r") as f: data = [json.loads(line) for line in f] - test_data_output_path = os.path.join(test_data_output, "test_data_set.jsonl") + test_data_output_path = test_data_output / Path("test_data_set.jsonl") clean_data_and_save(data, test_data_output_path) return test_data_output_path diff --git a/examples/gen_test_data/gen_test_data/requirements.txt b/examples/gen_test_data/requirements.txt similarity index 100% rename from examples/gen_test_data/gen_test_data/requirements.txt rename to examples/gen_test_data/requirements.txt diff --git a/examples/gen_test_data/gen_test_data/requirements_cloud.txt b/examples/gen_test_data/requirements_cloud.txt similarity index 100% rename from examples/gen_test_data/gen_test_data/requirements_cloud.txt rename to examples/gen_test_data/requirements_cloud.txt From 1efe84a1876dfdfe60f474a3bd445ade98ccd52d Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Thu, 1 Feb 2024 20:11:51 +0800 Subject: [PATCH 043/112] Fix clean data component (#1915) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- examples/gen_test_data/config.ini.example | 2 +- examples/gen_test_data/gen_test_data/utils/components.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index edcaca489da..02d2b3dde7f 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -30,5 +30,5 @@ aml_cluster = "" ; Parallel run step configs prs_instance_count = 2 -prs_mini_batch_size = "10kb" +prs_mini_batch_size = 2 prs_max_concurrency_per_instance = 10 diff --git a/examples/gen_test_data/gen_test_data/utils/components.py b/examples/gen_test_data/gen_test_data/utils/components.py index cdd0c04df9d..53232521b77 100644 --- a/examples/gen_test_data/gen_test_data/utils/components.py +++ b/examples/gen_test_data/gen_test_data/utils/components.py @@ -45,4 +45,4 @@ def clean_data_and_save_component( test_data_output_path = test_data_output / Path("test_data_set.jsonl") clean_data_and_save(data, test_data_output_path) - return test_data_output_path + return str(test_data_output_path) From 91066a369354f30978033409fdcf807cd889e332 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:03:21 +0800 Subject: [PATCH 044/112] improve log, prompt and dag (#1920) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --- .../generate_test_data_flow/flow.dag.yaml | 1 - .../score_text_trunk_prompt.jinja2 | 48 ++++++++++++------- .../validate_question.py | 2 +- .../validate_question_prompt.jinja2 | 4 +- .../validate_text_trunk.py | 2 +- examples/gen_test_data/gen_test_data/run.py | 15 ++++-- .../gen_test_data/utils/common.py | 30 ++++++------ 7 files changed, 61 insertions(+), 41 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 764124b61c7..436b03236fa 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -73,7 +73,6 @@ nodes: path: validate_question.py inputs: model_or_deployment_name: "" - response_format: json_object temperature: 0.2 max_tokens: "" generated_question: ${generate_question.output} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 index df143012ad5..374d2ceb1d6 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 @@ -1,35 +1,49 @@ # system: -Given a text trunk from a document as a context, complete the two following tasks and output a valid json format with the score and the reason. -Evaluate the provided context and assign a numerical score between 0 and 10 based on the following criteria: -1. Award a high score if: - (1) context delves into and explains concepts. - (2) context has information worthy of framing a question. -2. Award a lower score if if: - (1) context contains excessive references, acknowledgments, personal information. Some are acceptable, but too many will lower the score. - (2) context contains just punctuations or code snippet. - (3) context that is shorter than five words. +Given a text trunk from a document as context, perform the following tasks: -# user: +1. Exclude any references, acknowledgments, personal information, code snippets, or other non-essential elements from the original context. + +2. Evaluate the cleaned context against specific criteria for content quality and depth. + +3. Assign a numerical score between 0 and 10 based on the following criteria: + - Award a high score (closer to 10) if: + a) cleaned context delves into and explains concepts. + b) cleaned context contains substantial information that could lead to meaningful questions. + + - Award a lower score (closer to 0) if: + a) cleaned context is very brief, containing fewer than five words. + b) cleaned context is not meaningful. + + +4. Output a valid JSON containing the score and a reason. The reason must directly relate to the criteria outlined above, explaining the basis for the given score. -Output a JSON with both the score and the reason. The score and reason should totally based on the above criteria. Do not add any other criteria. The reason should be a string that explains why the score is given. Here are some examples: + +example 1: context: -"Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time." +Albert Einstein (14 March 1879 - 18 April 1955) was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time. + output: { - "score": "6.0", - "reason": "The context contains information worthy of framing a question." + "score": "8.0", + "reason": "The context provides substantial information that could lead to meaningful questions, hence the high score." } +example 2: context: -"Next step\n- Open the provided examples." +Next step\n- Open the provided examples. + output: { - "score": "2.0", - "reason": "The context lacks information about the provided example and previous steps." + "score": "0.0", + "reason": "The context lacks detailed information about the provided example and previous steps, resulting in a low score." } + +# user: + context: {{context}} + output: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index 6ef7d7e9411..9473625cdae 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -12,7 +12,7 @@ def validate_question( model_or_deployment_name: str, generated_question: str, validate_question_prompt: str, - response_format: str = ResponseFormat.JSON, + response_format: str = ResponseFormat.TEXT, temperature: float = 1.0, max_tokens: int = 512, ): diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 index 5eaa79ac56c..4b612fc5432 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 @@ -3,7 +3,9 @@ Verdict a question based on following rules: 1. If there are acronyms or terms in the question, then please check if they exist in the given context. If no, verdict no. If yes, check if other rules are satisfied. -2. Determine if the given question can be clearly understood and give the reason. Output a valid json with reason and verdict. +2. Determine if the given question can be clearly understood and give the reason. + +Output a valid json with reason and verdict. Here are some examples: question: What is the discovery about space? diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py index 90bb4804bd7..894fbef3324 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py @@ -13,7 +13,7 @@ def validate_text_trunk( score_text_trunk_prompt: str, score_threshold: float, context: str = None, - response_format: str = ResponseFormat.JSON, + response_format: str = ResponseFormat.TEXT, temperature: float = 1.0, max_tokens: int = 512, ): diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index c634522b9a6..c6d539300a8 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -31,7 +31,7 @@ def batch_run_flow( flow_batch_run_size: int, connection_name: str = "azure_open_ai_connection", ): - logger.info("Step 2: Start to batch run generate test data flow.") + logger.info("Step 2: Start to batch run 'generate_test_data_flow'...") base_run = pf.run( flow=flow_folder, data=flow_input_data, @@ -125,7 +125,6 @@ def run_local( output_folder, should_skip_split, ): - logger.info("Start to generate test data at local.") text_chunks_path = document_nodes_file inner_folder = os.path.join(output_folder, datetime.now().strftime("%b-%d-%Y-%H-%M-%S")) if not os.path.isdir(inner_folder): @@ -170,7 +169,6 @@ def run_cloud( prs_max_concurrency_per_instance, should_skip_split, ): - logger.info("Start to generate test data at cloud.") ml_client = get_ml_client(subscription_id, resource_group, workspace_name) if should_skip_split: @@ -236,11 +234,18 @@ def run_cloud( should_skip_split_documents = False if args.document_nodes_file and Path(args.document_nodes_file).is_file(): - logger.info("Received document node input file, skip step 1 'split documents to document nodes'.") - logger.info(f"Collect {count_non_blank_lines(args.document_nodes_file)} document nodes from document node input file.") should_skip_split_documents = True elif not args.documents_folder or not Path(args.documents_folder).is_dir(): parser.error("Either 'documents_folder' or 'document_nodes_file' should be specified correctly.") + + if args.cloud: + logger.info("Start to generate test data at cloud...") + else: + logger.info("Start to generate test data at local...") + + if should_skip_split_documents: + logger.info(f"Skip step 1 'Split documents to document nodes' as received document nodes from input file {args.document_nodes_file}.") + logger.info(f"Collect {count_non_blank_lines(args.document_nodes_file)} document nodes.") if args.cloud: run_cloud( diff --git a/examples/gen_test_data/gen_test_data/utils/common.py b/examples/gen_test_data/gen_test_data/utils/common.py index bb030c7896a..c381b8c00a2 100644 --- a/examples/gen_test_data/gen_test_data/utils/common.py +++ b/examples/gen_test_data/gen_test_data/utils/common.py @@ -18,30 +18,30 @@ def split_document(chunk_size, documents_folder, document_node_output): logger = get_logger("doc.split") - logger.info("Step 1: Split documents to document nodes.") - documents = SimpleDirectoryReader( - documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" - ).load_data() - logger.info(f"Collect {len(documents)} documents.") + logger.info("Step 1: Start to split documents to document nodes...") + # count the number of files in documents_folder, including subfolders, use pathlib + num_files = sum(1 for _ in Path(documents_folder).rglob("*") if _.is_file()) + logger.info(f"Found {num_files} files in the documents folder '{documents_folder}'. Using chunk size: {chunk_size} to split.") + # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. + # TODO: improve on top of `SimpleDirectoryReader` with a better chunking algorithm. + chunks = SimpleDirectoryReader(documents_folder, recursive=True, encoding="utf-8").load_data() # Convert documents into nodes node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) - documents = t.cast(t.List[LlamaindexDocument], documents) - document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - - logger.info(f"End to split the documents and generate {len(document_nodes)} document nodes.") + chunks = t.cast(t.List[LlamaindexDocument], chunks) + document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=chunks) + logger.info(f"Split the documents and created {len(document_nodes)} document nodes.") document_nodes_output_path = document_node_output / Path("document_nodes.jsonl") with open(document_nodes_output_path, "wt") as text_file: for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) - logger.info(f"Saved document nodes to {document_nodes_output_path}.") - + logger.info(f"Saved document nodes to '{document_nodes_output_path}'.") return str((Path(document_node_output) / "document_nodes.jsonl")) def clean_data_and_save(test_data_set: list, test_data_output_path: str): logger = get_logger("data.clean") - logger.info("Step 3: Clean invalid test data.") + logger.info("Step 3: Start to clean invalid test data...") logger.info(f"Collected {len(test_data_set)} test data after the batch run.") cleaned_data = [] @@ -55,9 +55,9 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): with open(test_data_output_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - logger.info( - f"Collected {len(cleaned_data)} valid test data. " - f"The cleaned data has been saved to {test_data_output_path}.") + # log debug info path. + logger.info(f"Removed {len(test_data_set) - len(cleaned_data)} invalid test data.") + logger.info(f"Saved {len(cleaned_data)} valid test data to {test_data_output_path}.") def count_non_blank_lines(file_path): From f1ea25ed73aa1ab513e19721eef967cb920e1d30 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:05:02 +0800 Subject: [PATCH 045/112] [data gen] lazy import all azure dependencies, remove connection_name, set prs component output mode as mount (#1924) lazy import all azure dependencies remove connection_name set prs component output mode as mount --- examples/gen_test_data/gen_test_data/run.py | 174 ++++++++++-------- .../gen_test_data/utils/constants.py | 8 - 2 files changed, 101 insertions(+), 81 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index c6d539300a8..22e32067207 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -4,8 +4,6 @@ from pathlib import Path import configargparse -from azure.ai.ml import Input, MLClient, dsl, load_component -from azure.identity import DefaultAzureCredential from promptflow import PFClient from promptflow._utils.logger_utils import get_logger @@ -18,8 +16,7 @@ os.sys.path.insert(0, UTILS_PATH) from common import clean_data_and_save, split_document, count_non_blank_lines # noqa: E402 -from components import clean_data_and_save_component, split_document_component # noqa: E402 -from constants import CONNECTIONS_TEMPLATE, TEXT_CHUNK # noqa: E402 +from constants import TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") @@ -29,7 +26,6 @@ def batch_run_flow( flow_folder: str, flow_input_data: str, flow_batch_run_size: int, - connection_name: str = "azure_open_ai_connection", ): logger.info("Step 2: Start to batch run 'generate_test_data_flow'...") base_run = pf.run( @@ -40,18 +36,12 @@ def batch_run_flow( "PF_WORKER_COUNT": str(flow_batch_run_size), "PF_BATCH_METHOD": "spawn", }, - connections={ - key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items() - }, column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, ) logger.info("Batch run is completed.") - return base_run - def get_batch_run_output(pf: PFClient, base_run: Run): logger.info(f"Start to get batch run {base_run.name} details.") details = pf.get_details(base_run, all_results=True) @@ -64,64 +54,12 @@ def get_batch_run_output(pf: PFClient, base_run: Run): ] -def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): - credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) - return MLClient( - credential=credential, - subscription_id=subscription_id, - resource_group_name=resource_group, - workspace_name=workspace_name, - ) - - -@dsl.pipeline( - non_pipeline_inputs=[ - "flow_yml_path", - "should_skip_doc_split", - "instance_count", - "mini_batch_size", - "max_concurrency_per_instance", - ] -) -def gen_test_data_pipeline( - data_input: Input, - flow_yml_path: str, - connection_name: str, - should_skip_doc_split: bool, - chunk_size=1024, - instance_count=1, - mini_batch_size="10kb", - max_concurrency_per_instance=2, -): - data = ( - data_input - if should_skip_doc_split - else split_document_component(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output - ) - - flow_node = load_component(flow_yml_path)( - data=data, - text_chunk="${data.text_chunk}", - connections={ - key: {"connection": value["connection"].format(connection_name=connection_name)} - for key, value in CONNECTIONS_TEMPLATE.items() - }, - ) - - flow_node.mini_batch_size = mini_batch_size - flow_node.max_concurrency_per_instance = max_concurrency_per_instance - flow_node.set_resources(instance_count=instance_count) - - clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs) - - def run_local( documents_folder, document_chunk_size, document_nodes_file, flow_folder, flow_batch_run_size, - connection_name, output_folder, should_skip_split, ): @@ -139,7 +77,6 @@ def run_local( flow_folder, text_chunks_path, flow_batch_run_size, - connection_name=connection_name, ) test_data_set = get_batch_run_output(pf, batch_run) @@ -159,7 +96,6 @@ def run_cloud( document_chunk_size, document_nodes_file, flow_folder, - connection_name, subscription_id, resource_group, workspace_name, @@ -169,12 +105,108 @@ def run_cloud( prs_max_concurrency_per_instance, should_skip_split, ): + # lazy import azure dependencies + from azure.ai.ml import Input as V2Input, MLClient, dsl, load_component + from azure.identity import DefaultAzureCredential + from mldesigner import Input, Output, command_component + from constants import ENVIRONMENT_DICT_FIXED_VERSION + + + @command_component( + name="split_document_component", + display_name="split documents", + description="Split documents into document nodes.", + environment=ENVIRONMENT_DICT_FIXED_VERSION, + ) + def split_document_component( + documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") + ) -> str: + """Split documents into document nodes. + + Args: + documents_folder: The folder containing documents to be split. + chunk_size: The size of each chunk. + document_node_output: The output folder + + Returns: + The folder containing the split documents. + """ + return split_document(chunk_size, documents_folder, document_node_output) + + + @command_component( + name="clean_data_and_save_component", + display_name="clean dataset", + description="Clean test data set to remove empty lines.", + environment=ENVIRONMENT_DICT_FIXED_VERSION, + ) + def clean_data_and_save_component( + test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") + ) -> str: + test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" + + with open(test_data_set_path, "r") as f: + data = [json.loads(line) for line in f] + + test_data_output_path = test_data_output / Path("test_data_set.jsonl") + clean_data_and_save(data, test_data_output_path) + + return str(test_data_output_path) + + + @dsl.pipeline( + non_pipeline_inputs=[ + "flow_yml_path", + "should_skip_doc_split", + "instance_count", + "mini_batch_size", + "max_concurrency_per_instance", + ] + ) + def gen_test_data_pipeline( + data_input: V2Input, + flow_yml_path: str, + should_skip_doc_split: bool, + chunk_size=1024, + instance_count=1, + mini_batch_size=1, + max_concurrency_per_instance=2, + ): + data = ( + data_input + if should_skip_doc_split + else split_document_component(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output + ) + flow_node = load_component(flow_yml_path)( + data=data, + text_chunk="${data.text_chunk}", + # connections={ + # key: {"connection": value["connection"].format(connection_name=connection_name)} + # for key, value in CONNECTIONS_TEMPLATE.items() + # }, + ) + flow_node.mini_batch_size = mini_batch_size + flow_node.max_concurrency_per_instance = max_concurrency_per_instance + flow_node.set_resources(instance_count=instance_count) + # Should use `mount` mode to ensure PRS complete merge output lines. + flow_node.outputs.flow_outputs.mode = "mount" + clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output + + def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): + credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) + return MLClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group, + workspace_name=workspace_name, + ) + ml_client = get_ml_client(subscription_id, resource_group, workspace_name) if should_skip_split: - data_input = Input(path=document_nodes_file, type="uri_file") + data_input = V2Input(path=document_nodes_file, type="uri_file") else: - data_input = Input(path=documents_folder, type="uri_folder") + data_input = V2Input(path=documents_folder, type="uri_folder") prs_configs = { "instance_count": prs_instance_count, @@ -185,7 +217,6 @@ def run_cloud( pipeline_with_flow = gen_test_data_pipeline( data_input=data_input, flow_yml_path=os.path.join(flow_folder, "flow.dag.yaml"), - connection_name=connection_name, should_skip_doc_split=should_skip_split, chunk_size=document_chunk_size, **prs_configs, @@ -217,7 +248,6 @@ def run_cloud( type=int, help="Test data generation flow batch run size, default is 16", ) - parser.add_argument("--connection_name", required=True, type=str, help="Promptflow connection name") # Configs for local parser.add_argument("--output_folder", type=str, help="Output folder path.") # Configs for cloud @@ -244,8 +274,8 @@ def run_cloud( logger.info("Start to generate test data at local...") if should_skip_split_documents: - logger.info(f"Skip step 1 'Split documents to document nodes' as received document nodes from input file {args.document_nodes_file}.") - logger.info(f"Collect {count_non_blank_lines(args.document_nodes_file)} document nodes.") + logger.info(f"Skip step 1 'Split documents to document nodes' as received document nodes from input file '{args.document_nodes_file}'.") + logger.info(f"Collected {count_non_blank_lines(args.document_nodes_file)} document nodes.") if args.cloud: run_cloud( @@ -253,7 +283,6 @@ def run_cloud( args.document_chunk_size, args.document_nodes_file, args.flow_folder, - args.connection_name, args.subscription_id, args.resource_group, args.workspace_name, @@ -270,7 +299,6 @@ def run_cloud( args.document_nodes_file, args.flow_folder, args.flow_batch_run_size, - args.connection_name, args.output_folder, should_skip_split_documents, ) diff --git a/examples/gen_test_data/gen_test_data/utils/constants.py b/examples/gen_test_data/gen_test_data/utils/constants.py index b8f67a943c8..b93b18ea09c 100644 --- a/examples/gen_test_data/gen_test_data/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/utils/constants.py @@ -13,11 +13,3 @@ ], }, ) - -CONNECTIONS_TEMPLATE = { - "validate_text_trunk": {"connection": "{connection_name}"}, - "generate_question": {"connection": "{connection_name}"}, - "validate_question": {"connection": "{connection_name}"}, - "generate_suggested_answer": {"connection": "{connection_name}"}, - "validate_suggested_answer": {"connection": "{connection_name}"}, -} From f405a7c85d5449f064006ecd32aa19e766ab5f24 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:44:01 +0800 Subject: [PATCH 046/112] [data gen] fix mldesigner cannot find component issue (#1928) fix mldesigner cannot find component issue --- .../gen_test_data/{utils => }/common.py | 20 +++--- .../gen_test_data/{utils => }/components.py | 0 .../gen_test_data/{utils => }/constants.py | 2 +- examples/gen_test_data/gen_test_data/run.py | 64 ++++--------------- 4 files changed, 25 insertions(+), 61 deletions(-) rename examples/gen_test_data/gen_test_data/{utils => }/common.py (86%) rename examples/gen_test_data/gen_test_data/{utils => }/components.py (100%) rename examples/gen_test_data/gen_test_data/{utils => }/constants.py (90%) diff --git a/examples/gen_test_data/gen_test_data/utils/common.py b/examples/gen_test_data/gen_test_data/common.py similarity index 86% rename from examples/gen_test_data/gen_test_data/utils/common.py rename to examples/gen_test_data/gen_test_data/common.py index c381b8c00a2..4b46c73493d 100644 --- a/examples/gen_test_data/gen_test_data/utils/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -5,18 +5,18 @@ from constants import DOCUMENT_NODE, TEXT_CHUNK from promptflow._utils.logger_utils import get_logger -try: - from llama_index import SimpleDirectoryReader - from llama_index.node_parser import SentenceSplitter - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - def split_document(chunk_size, documents_folder, document_node_output): + try: + from llama_index import SimpleDirectoryReader + from llama_index.node_parser import SentenceSplitter + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode + except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + logger = get_logger("doc.split") logger.info("Step 1: Start to split documents to document nodes...") # count the number of files in documents_folder, including subfolders, use pathlib diff --git a/examples/gen_test_data/gen_test_data/utils/components.py b/examples/gen_test_data/gen_test_data/components.py similarity index 100% rename from examples/gen_test_data/gen_test_data/utils/components.py rename to examples/gen_test_data/gen_test_data/components.py diff --git a/examples/gen_test_data/gen_test_data/utils/constants.py b/examples/gen_test_data/gen_test_data/constants.py similarity index 90% rename from examples/gen_test_data/gen_test_data/utils/constants.py rename to examples/gen_test_data/gen_test_data/constants.py index b93b18ea09c..b057590711f 100644 --- a/examples/gen_test_data/gen_test_data/utils/constants.py +++ b/examples/gen_test_data/gen_test_data/constants.py @@ -9,7 +9,7 @@ "dependencies": [ "python=3.10.12", "pip=23.2.1", - {"pip": ["mldesigner==0.1.0b17", "llama_index", "docx2txt", "promptflow"]}, + {"pip": ["mldesigner==0.1.0b17", "llama_index", "docx2txt", "promptflow", "configargparse"]}, ], }, ) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 22e32067207..0a9b079d26c 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -11,9 +11,8 @@ CONFIG_FILE = (Path(__file__).parents[1] / "config.ini").resolve() -UTILS_PATH = os.path.abspath(Path(__file__).parents[0] / "utils") -if UTILS_PATH not in os.sys.path: - os.sys.path.insert(0, UTILS_PATH) +# in order to import from absoluate path, which is required by mldesigner +os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) from common import clean_data_and_save, split_document, count_non_blank_lines # noqa: E402 from constants import TEXT_CHUNK # noqa: E402 @@ -42,6 +41,7 @@ def batch_run_flow( logger.info("Batch run is completed.") return base_run + def get_batch_run_output(pf: PFClient, base_run: Run): logger.info(f"Start to get batch run {base_run.name} details.") details = pf.get_details(base_run, all_results=True) @@ -106,53 +106,15 @@ def run_cloud( should_skip_split, ): # lazy import azure dependencies - from azure.ai.ml import Input as V2Input, MLClient, dsl, load_component - from azure.identity import DefaultAzureCredential - from mldesigner import Input, Output, command_component - from constants import ENVIRONMENT_DICT_FIXED_VERSION - - - @command_component( - name="split_document_component", - display_name="split documents", - description="Split documents into document nodes.", - environment=ENVIRONMENT_DICT_FIXED_VERSION, - ) - def split_document_component( - documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") - ) -> str: - """Split documents into document nodes. - - Args: - documents_folder: The folder containing documents to be split. - chunk_size: The size of each chunk. - document_node_output: The output folder - - Returns: - The folder containing the split documents. - """ - return split_document(chunk_size, documents_folder, document_node_output) - - - @command_component( - name="clean_data_and_save_component", - display_name="clean dataset", - description="Clean test data set to remove empty lines.", - environment=ENVIRONMENT_DICT_FIXED_VERSION, - ) - def clean_data_and_save_component( - test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") - ) -> str: - test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" - - with open(test_data_set_path, "r") as f: - data = [json.loads(line) for line in f] - - test_data_output_path = test_data_output / Path("test_data_set.jsonl") - clean_data_and_save(data, test_data_output_path) - - return str(test_data_output_path) - + try: + from azure.ai.ml import Input as V2Input, MLClient, dsl, load_component + from azure.identity import DefaultAzureCredential + from constants import ENVIRONMENT_DICT_FIXED_VERSION + except ImportError: + raise ImportError( + "Please install azure dependencies using the following command: " + + "`pip install -r requirements_cloud.txt`" + ) @dsl.pipeline( non_pipeline_inputs=[ @@ -172,6 +134,7 @@ def gen_test_data_pipeline( mini_batch_size=1, max_concurrency_per_instance=2, ): + from components import split_document_component, clean_data_and_save_component data = ( data_input if should_skip_doc_split @@ -188,6 +151,7 @@ def gen_test_data_pipeline( flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance flow_node.set_resources(instance_count=instance_count) + # flow_node.allowed_failed_count = -1 # Should use `mount` mode to ensure PRS complete merge output lines. flow_node.outputs.flow_outputs.mode = "mount" clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output From e17e9929c8da1c9dd876ad5af771d2febfaaf10b Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:46:14 +0800 Subject: [PATCH 047/112] Seprate cloud part (#1926) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: yalu4 --- .../cloud/azureai/generate-test-data-cloud.md | 38 ++++++++++++++ docs/how-to-guides/generate-test-data.md | 14 +----- examples/gen_test_data/conda.yml | 12 +++++ examples/gen_test_data/config.ini.example | 3 ++ .../gen_test_data/gen_test_data/components.py | 20 +++++--- .../gen_test_data/gen_test_data/constants.py | 13 ----- examples/gen_test_data/gen_test_data/run.py | 50 +++++++++++++++---- 7 files changed, 107 insertions(+), 43 deletions(-) create mode 100644 docs/cloud/azureai/generate-test-data-cloud.md create mode 100644 examples/gen_test_data/conda.yml diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md new file mode 100644 index 00000000000..695b0aa16fb --- /dev/null +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -0,0 +1,38 @@ +# How to generate test data in cloud based on documents +This guide will help you learn how to generate test data on Azure AI, so that you can integrate the created flow and process a large amount of data. + + +## Prerequisites + +1. Go through local test data generation [guide](../../how-to-guides/generate-test-data.md) and prepare your test data generation flow. +2. Go to the [gen_test_data](../../../examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. +3. Prepare cloud environment. + - Navigate to file [conda.yml](../../../examples/gen_test_data/conda.yml). + - For specific document file types, you may need to add extra packages in `conda.yml`: + > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + - .docx - `docx2txt` + - .pdf - `pypdf` + - .ipynb - `nbconvert` + +4. Prepare Azure AI resources in cloud. + - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). + - A compute target - [Learn more about compute cluster](https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2). +5. Create cloud connection: [Create a connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start.html#create-necessary-connections) +6. Prepare config.ini + - Navigate to [gen_test_data](../../../examples/gen_test_data) folder. + - Run command to copy `config.ini.example` and update the configurations in the `configs.ini` file + ``` + cp config.ini.example config.ini + ``` + - Fill in the values in `COMMON` and `CLOUD` section. + + +## Generate test data at cloud +For handling larger test data, you can leverage the PRS component to run flow in cloud. +- Navigate to [gen_test_data](../../../examples/gen_test_data) folder. +- After configuration, run the following command to generate the test data set: + ```bash + python -m gen_test_data.run --cloud + ``` + +- The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 0afe4a50795..9a2d5920165 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -74,16 +74,4 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene ## Generate test data at cloud -For handling larger test data, you can leverage the PRS component to run flow in pipeline. -- Navigate to [gen_test_data](../../examples/gen_test_data_gen) folder. - -- Run command to copy `config.ini.example` and update the `COMMON` and `CLOUD` configurations in the `configs.ini` file - ``` - cp config.ini.example config.ini - ``` -- After configuration, run the following command to generate the test data set: - ```bash - python -m gen_test_data.run --cloud - ``` - -- The generated test data will be a data asset which can be found in the output of the last node. You can register this data asset for future use. +For handling larger test data, you can leverage the PRS component to run flow in cloud. Please refer to this [guide](../cloud/azureai/generate-test-data-cloud.md) for more information. diff --git a/examples/gen_test_data/conda.yml b/examples/gen_test_data/conda.yml new file mode 100644 index 00000000000..bb92055351b --- /dev/null +++ b/examples/gen_test_data/conda.yml @@ -0,0 +1,12 @@ +name: test_data_gen_conda_env +channels: + - defaults +dependencies: + - python=3.10.12 + - pip=23.2.1 + - pip: + - mldesigner + - configargparse + - llama_index + - docx2txt + - promptflow diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index 02d2b3dde7f..c940efe059e 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -32,3 +32,6 @@ aml_cluster = "" prs_instance_count = 2 prs_mini_batch_size = 2 prs_max_concurrency_per_instance = 10 +prs_max_retry_count = 3 +prs_run_invocation_time = 800 +prs_allowed_failed_count = -1 diff --git a/examples/gen_test_data/gen_test_data/components.py b/examples/gen_test_data/gen_test_data/components.py index 53232521b77..d4bd4c3658d 100644 --- a/examples/gen_test_data/gen_test_data/components.py +++ b/examples/gen_test_data/gen_test_data/components.py @@ -1,19 +1,24 @@ import json from pathlib import Path +from common import clean_data_and_save, split_document from mldesigner import Input, Output, command_component -from common import split_document, clean_data_and_save -from constants import ENVIRONMENT_DICT_FIXED_VERSION + +conda_file = Path(__file__).parent.parent / "conda.yml" +env_image = "mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04" @command_component( name="split_document_component", display_name="split documents", description="Split documents into document nodes.", - environment=ENVIRONMENT_DICT_FIXED_VERSION, + environment=dict( + conda_file=conda_file, + image=env_image, + ), ) def split_document_component( - documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") + documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") ) -> str: """Split documents into document nodes. @@ -32,10 +37,13 @@ def split_document_component( name="clean_data_and_save_component", display_name="clean dataset", description="Clean test data set to remove empty lines.", - environment=ENVIRONMENT_DICT_FIXED_VERSION, + environment=dict( + conda_file=conda_file, + image=env_image, + ), ) def clean_data_and_save_component( - test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") + test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") ) -> str: test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" diff --git a/examples/gen_test_data/gen_test_data/constants.py b/examples/gen_test_data/gen_test_data/constants.py index b057590711f..e3e6d1de170 100644 --- a/examples/gen_test_data/gen_test_data/constants.py +++ b/examples/gen_test_data/gen_test_data/constants.py @@ -1,15 +1,2 @@ DOCUMENT_NODE = "document_node" TEXT_CHUNK = "text_chunk" - -ENVIRONMENT_DICT_FIXED_VERSION = dict( - image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", - conda_file={ - "name": "test_data_gen_conda_env", - "channels": ["defaults"], - "dependencies": [ - "python=3.10.12", - "pip=23.2.1", - {"pip": ["mldesigner==0.1.0b17", "llama_index", "docx2txt", "promptflow", "configargparse"]}, - ], - }, -) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 0a9b079d26c..65c53bc521a 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -11,10 +11,10 @@ CONFIG_FILE = (Path(__file__).parents[1] / "config.ini").resolve() -# in order to import from absoluate path, which is required by mldesigner +# in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) -from common import clean_data_and_save, split_document, count_non_blank_lines # noqa: E402 +from common import clean_data_and_save, count_non_blank_lines, split_document # noqa: E402 from constants import TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") @@ -83,7 +83,7 @@ def run_local( # Store intermedian batch run output results jsonl_str = "\n".join(map(json.dumps, test_data_set)) - intermedian_batch_run_res = os.path.join(inner_folder, "batch-run-result.jsonl") + intermedian_batch_run_res = os.path.join(inner_folder, "test-data-gen-details.jsonl") with open(intermedian_batch_run_res, "wt") as text_file: print(f"{jsonl_str}", file=text_file) @@ -103,13 +103,17 @@ def run_cloud( prs_instance_count, prs_mini_batch_size, prs_max_concurrency_per_instance, + prs_max_retry_count, + prs_run_invocation_time, + prs_allowed_failed_count, should_skip_split, ): # lazy import azure dependencies try: - from azure.ai.ml import Input as V2Input, MLClient, dsl, load_component + from azure.ai.ml import Input as V2Input + from azure.ai.ml import MLClient, dsl, load_component + from azure.ai.ml.entities import RetrySettings from azure.identity import DefaultAzureCredential - from constants import ENVIRONMENT_DICT_FIXED_VERSION except ImportError: raise ImportError( "Please install azure dependencies using the following command: " @@ -123,6 +127,9 @@ def run_cloud( "instance_count", "mini_batch_size", "max_concurrency_per_instance", + "max_retry_count", + "run_invocation_time", + "allowed_failed_count", ] ) def gen_test_data_pipeline( @@ -133,12 +140,18 @@ def gen_test_data_pipeline( instance_count=1, mini_batch_size=1, max_concurrency_per_instance=2, + max_retry_count=3, + run_invocation_time=600, + allowed_failed_count=-1, ): - from components import split_document_component, clean_data_and_save_component + from components import clean_data_and_save_component, split_document_component + data = ( data_input if should_skip_doc_split - else split_document_component(documents_folder=data_input, chunk_size=chunk_size).outputs.document_node_output + else split_document_component( + documents_folder=data_input, chunk_size=chunk_size + ).outputs.document_node_output ) flow_node = load_component(flow_yml_path)( data=data, @@ -151,7 +164,8 @@ def gen_test_data_pipeline( flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance flow_node.set_resources(instance_count=instance_count) - # flow_node.allowed_failed_count = -1 + flow_node.retry_settings = RetrySettings(max_retry_count=max_retry_count, timeout=run_invocation_time) + flow_node.mini_batch_error_threshold = allowed_failed_count # Should use `mount` mode to ensure PRS complete merge output lines. flow_node.outputs.flow_outputs.mode = "mount" clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output @@ -176,6 +190,9 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str "instance_count": prs_instance_count, "mini_batch_size": prs_mini_batch_size, "max_concurrency_per_instance": prs_max_concurrency_per_instance, + "max_retry_count": prs_max_retry_count, + "run_invocation_time": prs_run_invocation_time, + "allowed_failed_count": prs_allowed_failed_count, } pipeline_with_flow = gen_test_data_pipeline( @@ -224,6 +241,11 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str parser.add_argument( "--prs_max_concurrency_per_instance", type=int, help="Parallel run step max concurrency per instance" ) + parser.add_argument("--prs_max_retry_count", type=int, help="Parallel run step max retry count") + parser.add_argument("--prs_run_invocation_time", type=int, help="Parallel run step run invocation time") + parser.add_argument( + "--prs_allowed_failed_count", type=int, help="Number of failed mini batches that could be ignored" + ) args = parser.parse_args() should_skip_split_documents = False @@ -231,14 +253,17 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str should_skip_split_documents = True elif not args.documents_folder or not Path(args.documents_folder).is_dir(): parser.error("Either 'documents_folder' or 'document_nodes_file' should be specified correctly.") - + if args.cloud: logger.info("Start to generate test data at cloud...") else: logger.info("Start to generate test data at local...") - + if should_skip_split_documents: - logger.info(f"Skip step 1 'Split documents to document nodes' as received document nodes from input file '{args.document_nodes_file}'.") + logger.info( + "Skip step 1 'Split documents to document nodes' as received document nodes from " + f"input file '{args.document_nodes_file}'." + ) logger.info(f"Collected {count_non_blank_lines(args.document_nodes_file)} document nodes.") if args.cloud: @@ -254,6 +279,9 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str args.prs_instance_count, args.prs_mini_batch_size, args.prs_max_concurrency_per_instance, + args.prs_max_retry_count, + args.prs_run_invocation_time, + args.prs_allowed_failed_count, should_skip_split_documents, ) else: From feb8063fa5d2875ecb3914154d97d565b4c5bc7c Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Sun, 4 Feb 2024 09:30:32 +0800 Subject: [PATCH 048/112] [data gen] streaming log batch run progress, modify debug info, modify doc, wording, update tool, remove text_meta (#1934) ![image](https://github.com/microsoft/promptflow/assets/49483542/bfc380a8-b3ce-45fb-8610-b6718fd378e6) --- .../cloud/azureai/generate-test-data-cloud.md | 23 ++--- docs/how-to-guides/generate-test-data.md | 72 +++++++-------- examples/gen_test_data/config.ini.example | 4 +- .../gen_test_data/gen_test_data/common.py | 56 ++++++++++-- .../gen_test_data/gen_test_data/components.py | 8 +- .../gen_test_data/gen_test_data/constants.py | 1 + .../generate_test_data_flow/flow.dag.yaml | 29 +++--- .../generate_debug_info.py | 45 +++++----- .../generate_question.py | 6 +- .../generate_suggested_answer.py | 2 +- ....jinja2 => score_text_chunk_prompt.jinja2} | 2 +- .../generate_test_data_flow/utils.py | 60 +++---------- .../validate_question.py | 6 +- .../validate_suggested_answer.py | 4 +- ...e_text_trunk.py => validate_text_chunk.py} | 22 ++--- examples/gen_test_data/gen_test_data/run.py | 89 ++++++++++--------- .../gen_test_data/utils/__init__.py | 0 .../gen_test_data/utils/analyze_data.py | 50 ----------- 18 files changed, 213 insertions(+), 266 deletions(-) rename examples/gen_test_data/gen_test_data/generate_test_data_flow/{score_text_trunk_prompt.jinja2 => score_text_chunk_prompt.jinja2} (95%) rename examples/gen_test_data/gen_test_data/generate_test_data_flow/{validate_text_trunk.py => validate_text_chunk.py} (56%) delete mode 100644 examples/gen_test_data/gen_test_data/utils/__init__.py delete mode 100644 examples/gen_test_data/gen_test_data/utils/analyze_data.py diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index 695b0aa16fb..9cb5bcf749b 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -4,27 +4,28 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Prerequisites -1. Go through local test data generation [guide](../../how-to-guides/generate-test-data.md) and prepare your test data generation flow. -2. Go to the [gen_test_data](../../../examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. +1. Go through [local test data generation guide](../../how-to-guides/generate-test-data.md) and prepare your [test data generation flow](../../../examples/gen_test_data/gen_test_data/generate_test_data_flow/). +2. Go to the [example_gen_test_data](../../../examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. 3. Prepare cloud environment. - Navigate to file [conda.yml](../../../examples/gen_test_data/conda.yml). - - For specific document file types, you may need to add extra packages in `conda.yml`: - > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). - - .docx - `docx2txt` - - .pdf - `pypdf` - - .ipynb - `nbconvert` + - For specific document file types, you may need to install extra packages: + - .docx - `pip install docx2txt` + - .pdf - `pip install pypdf` + - .ipynb - `pip install nbconvert` + > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). 4. Prepare Azure AI resources in cloud. - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). - A compute target - [Learn more about compute cluster](https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2). -5. Create cloud connection: [Create a connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start.html#create-necessary-connections) +5. [Create cloud connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start.html#create-necessary-connections) + 6. Prepare config.ini - - Navigate to [gen_test_data](../../../examples/gen_test_data) folder. - - Run command to copy `config.ini.example` and update the configurations in the `configs.ini` file + - Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. + - Run command to copy [`config.ini.example`](../../../examples/gen_test_data/config.ini.example). ``` cp config.ini.example config.ini ``` - - Fill in the values in `COMMON` and `CLOUD` section. + - Update the configurations in the `configs.ini`. Fill in the values in `COMMON` and `CLOUD` section following inline comment instruction. ## Generate test data at cloud diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 9a2d5920165..14979bfc346 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -1,6 +1,6 @@ # How to generate test data based on documents -This guide will instruct you on how to generate test data for RAG systems using pre-existing documents. -This approach eliminates the need for manual data creation, which is typically time-consuming and labor-intensive, or the expensive option of purchasing pre-packaged test data. +In this doc, you may learn how to generate test data based on your documents for RAG app. +This approach helps relieve the efforts of manual data creation, which is typically time-consuming and labor-intensive, or the expensive option of purchasing pre-packaged test data. By leveraging the capabilities of llm, this guide streamlines the test data generation process, making it more efficient and cost-effective. @@ -14,64 +14,60 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene **Limitations:** - - While the test data generator works well with standard documents, it may face challenges with API introduction documents or reference documents. - - The test data generator may not function effectively for non-Latin characters, such as Chinese. These limitations may be due to the text loader capabilities, such as `pypdf`. + - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. + - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Go to the [gen_test_data](../../examples/gen_test_data) folder and install required packages. - - Run in local: `pip install -r requirements.txt` - - Run in cloud: `pip install -r requirements_cloud.txt` +2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages `pip install -r requirements.txt` - For specific document file types, you will need to install extra packages: - > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + For specific document file types, you may need to install extra packages: - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` - .ipynb - `pip install nbconvert` + > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + +3. Install VSCode extension `Prompt flow`. -3. Install VSCode extension and create connections refer to [Create a connection](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) +4. [Create connections](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) + +5. Prepare config.ini + - Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. + - Run command to copy [`config.ini.example`](../../examples/gen_test_data/config.ini.example). + ``` + cp config.ini.example config.ini + ``` + - Update the configurations in the `configs.ini`. Fill in the values in `COMMON` and `LOCAL` section following inline comment instruction. ## Create a test data generation flow - - Open the [generate_test_data_flow](../../examples/gen_test_data/generate_test_data_flow/) folder in VSCode. + - Open the [sample test data generation flow](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/) in VSCode. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. + - Fill in node inputs including `connection`, `model_or_deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to set the `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. - [*Optional*] Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). **Understand the prompts** - The test data generation flow contains five different prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text trunk, generated question or answer. + The test data generation flow contains 4 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - - *generate question prompt*: frame a question based on the given text trunk. - - *generate suggested answer prompt*: generate suggested answer for the question based on the given text trunk. + - [*generate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - *score text trunk prompt*: validate if the given text trunk is worthy of framing a question. If the score is lower than score_threshold, validation fails. - - *validate seed/test question prompt*: validate if the generated question can be clearly understood. - - *validate suggested answer*: validate if the generated suggested answer is clear and certain. - - If the validation fails, the corresponding output would be an empty string so that the invalid data would not be incorporated into the final test data set. - - - - - Fill in the necessary flow/node inputs, and run the flow in VSCode refering to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + - [*score text chunk prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (default 4), validation fails. + - [*validate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. - **Set the appropriate model and corresponding response format.** The `gpt-4` model is recommended. The default prompt may yield better results with this model compared to the gpt-3 series. - - For the `gpt-4` model with version `0613`, use the response format `text`. - - For the `gpt-4` model with version `1106`, use the response format `json`. + If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. +## Generate test data +- Navigate to [example_gen_test_data](../../examples/gen_test_data_gen) folder. -## Generate test data at local -- Navigate to [gen_test_data](../../examples/gen_test_data_gen) folder. - -- Run command to copy `config.ini.example` and update the `COMMON` and `LOCAL` configurations in the `configs.ini` file - ``` - cp config.ini.example config.ini - ``` - - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run - ``` -- The generated test data will be a data jsonl file located in the path you configured in `config.ini`. + ``` +- The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. -## Generate test data at cloud -For handling larger test data, you can leverage the PRS component to run flow in cloud. Please refer to this [guide](../cloud/azureai/generate-test-data-cloud.md) for more information. +If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](../cloud/azureai/generate-test-data-cloud.md) for more detailed steps. diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index c940efe059e..234b298f9ed 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -18,7 +18,7 @@ connection_name = "" [LOCAL] ; This section is for local test data generation related configuration. output_folder = "" -flow_batch_run_size = 10 +flow_batch_run_size = 4 [CLOUD] @@ -31,7 +31,7 @@ aml_cluster = "" ; Parallel run step configs prs_instance_count = 2 prs_mini_batch_size = 2 -prs_max_concurrency_per_instance = 10 +prs_max_concurrency_per_instance = 4 prs_max_retry_count = 3 prs_run_invocation_time = 800 prs_allowed_failed_count = -1 diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 4b46c73493d..623827efdda 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -1,4 +1,7 @@ import json +import sys +import re +import time import typing as t from pathlib import Path @@ -19,7 +22,7 @@ def split_document(chunk_size, documents_folder, document_node_output): logger = get_logger("doc.split") logger.info("Step 1: Start to split documents to document nodes...") - # count the number of files in documents_folder, including subfolders, use pathlib + # count the number of files in documents_folder, including subfolders. num_files = sum(1 for _ in Path(documents_folder).rglob("*") if _.is_file()) logger.info(f"Found {num_files} files in the documents folder '{documents_folder}'. Using chunk size: {chunk_size} to split.") # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. @@ -39,7 +42,7 @@ def split_document(chunk_size, documents_folder, document_node_output): return str((Path(document_node_output) / "document_nodes.jsonl")) -def clean_data_and_save(test_data_set: list, test_data_output_path: str): +def clean_data(test_data_set: list, test_data_output_path: str): logger = get_logger("data.clean") logger.info("Step 3: Start to clean invalid test data...") logger.info(f"Collected {len(test_data_set)} test data after the batch run.") @@ -49,15 +52,17 @@ def clean_data_and_save(test_data_set: list, test_data_output_path: str): if test_data and all( val and val != "(Failed)" for key, val in test_data.items() if key.lower() != "line_number" ): - cleaned_data.append(test_data) + data_line = {"question": test_data["question"], "suggested_answer": test_data["suggested_answer"]} + cleaned_data.append(data_line) jsonl_str = "\n".join(map(json.dumps, cleaned_data)) with open(test_data_output_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) + # TODO: aggregate invalid data root cause and count, and log it. # log debug info path. - logger.info(f"Removed {len(test_data_set) - len(cleaned_data)} invalid test data.") - logger.info(f"Saved {len(cleaned_data)} valid test data to {test_data_output_path}.") + logger.info(f"Removed {len(test_data_set) - len(cleaned_data)} invalid test data. " + f"Saved {len(cleaned_data)} valid test data to '{test_data_output_path}'.") def count_non_blank_lines(file_path): @@ -65,4 +70,43 @@ def count_non_blank_lines(file_path): lines = file.readlines() non_blank_lines = len([line for line in lines if line.strip()]) - return non_blank_lines \ No newline at end of file + return non_blank_lines + + +def print_progress(log_file_path: str): + logger = get_logger("data.gen") + logger.info(f"Showing progress log, or you can click '{log_file_path}' and see detailed batch run log...") + log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") + # wait for the log file to be created + start_time = time.time() + while not Path(log_file_path).is_file(): + time.sleep(1) + # if the log file is not created within 5 minutes, raise an error + if time.time() - start_time > 300: + raise Exception(f"Log file '{log_file_path}' is not created within 5 minutes.") + + try: + last_data_time = time.time() + with open(log_file_path, 'r') as f: + while True: + line = f.readline().strip() + if line: + last_data_time = time.time() # Update the time when the last data was received + match = log_pattern.match(line) + if not match: + continue + + sys.stdout.write("\r" + line) # \r will move the cursor back to the beginning of the line + sys.stdout.flush() # flush the buffer to ensure the log is displayed immediately + finished, total = map(int, match.groups()) + if finished == total: + logger.info("Batch run is completed.") + break + elif time.time() - last_data_time > 300: + logger.info("No new log line received for 5 minutes. Stop reading. See the log file for more details.") + break # Stop reading + else: + time.sleep(1) # wait for 1 second if no new line is available + except KeyboardInterrupt: + sys.stdout.write("\n") # ensure to start on a new line when the user interrupts + sys.stdout.flush() diff --git a/examples/gen_test_data/gen_test_data/components.py b/examples/gen_test_data/gen_test_data/components.py index d4bd4c3658d..ce55f51efe2 100644 --- a/examples/gen_test_data/gen_test_data/components.py +++ b/examples/gen_test_data/gen_test_data/components.py @@ -1,7 +1,7 @@ import json from pathlib import Path -from common import clean_data_and_save, split_document +from common import clean_data, split_document from mldesigner import Input, Output, command_component conda_file = Path(__file__).parent.parent / "conda.yml" @@ -34,7 +34,7 @@ def split_document_component( @command_component( - name="clean_data_and_save_component", + name="clean_data_component", display_name="clean dataset", description="Clean test data set to remove empty lines.", environment=dict( @@ -42,7 +42,7 @@ def split_document_component( image=env_image, ), ) -def clean_data_and_save_component( +def clean_data_component( test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") ) -> str: test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" @@ -51,6 +51,6 @@ def clean_data_and_save_component( data = [json.loads(line) for line in f] test_data_output_path = test_data_output / Path("test_data_set.jsonl") - clean_data_and_save(data, test_data_output_path) + clean_data(data, test_data_output_path) return str(test_data_output_path) diff --git a/examples/gen_test_data/gen_test_data/constants.py b/examples/gen_test_data/gen_test_data/constants.py index e3e6d1de170..e6616180bd6 100644 --- a/examples/gen_test_data/gen_test_data/constants.py +++ b/examples/gen_test_data/gen_test_data/constants.py @@ -1,2 +1,3 @@ DOCUMENT_NODE = "document_node" TEXT_CHUNK = "text_chunk" +DETAILS_FILE_NAME ="test-data-gen-details.jsonl" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 436b03236fa..36a3baa9acf 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -5,10 +5,9 @@ inputs: text_chunk: type: string is_chat_input: false - default: "" - text_meta: - type: string - default: "{}" + default: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born + theoretical physicist who is widely held to be one of the greatest and + most influential scientists of all time. outputs: question: type: string @@ -20,11 +19,11 @@ outputs: type: string reference: ${generate_debug_info.output} nodes: -- name: score_text_trunk_prompt +- name: score_text_chunk_prompt type: prompt source: type: code - path: score_text_trunk_prompt.jinja2 + path: score_text_chunk_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false @@ -61,9 +60,8 @@ nodes: path: generate_question.py inputs: model_or_deployment_name: "" - context: ${validate_text_trunk.output.context} + context: ${validate_text_chunk.output.context} temperature: 0.2 - max_tokens: "" generate_question_prompt: ${generate_question_prompt.output} use_variants: false - name: validate_question @@ -74,7 +72,6 @@ nodes: inputs: model_or_deployment_name: "" temperature: 0.2 - max_tokens: "" generated_question: ${generate_question.output} validate_question_prompt: ${validate_question_prompt.output} use_variants: false @@ -89,7 +86,6 @@ nodes: question: ${validate_question.output.question} model_or_deployment_name: "" temperature: 0.2 - max_tokens: "" use_variants: false - name: generate_debug_info type: python @@ -98,10 +94,9 @@ nodes: path: generate_debug_info.py inputs: question_type: ${validate_question.output.question_type} - text_trunk: ${inputs.text_chunk} - text_meta: ${inputs.text_meta} + text_chunk: ${inputs.text_chunk} validate_suggested_answer_output: ${validate_suggested_answer.output} - text_trunk_validation_res: ${validate_text_trunk.output.validation_res} + text_chunk_validation_res: ${validate_text_chunk.output.validation_res} validate_question_output: ${validate_question.output} - name: validate_suggested_answer_prompt type: prompt @@ -120,16 +115,14 @@ nodes: suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} temperature: 0.2 - max_tokens: "" -- name: validate_text_trunk +- name: validate_text_chunk type: python source: type: code - path: validate_text_trunk.py + path: validate_text_chunk.py inputs: - score_text_trunk_prompt: ${score_text_trunk_prompt.output} + score_text_chunk_prompt: ${score_text_chunk_prompt.output} context: ${inputs.text_chunk} score_threshold: 4 model_or_deployment_name: "" temperature: 0.2 - max_tokens: "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index 1a610cc6e4a..fd703204772 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -9,9 +9,8 @@ @tool def my_python_tool( question_type: str, - text_trunk: str, - text_meta: dict = None, - text_trunk_validation_res: ValidationResult = None, + text_chunk: str, + text_chunk_validation_res: ValidationResult = None, validate_question_output: dict = None, validate_suggested_answer_output: dict = None, ) -> dict: @@ -22,7 +21,7 @@ def my_python_tool( suggested_answer_validation_res = validate_suggested_answer_output["validation_res"] is_generation_success = generated_suggested_answer != "" - is_text_trunk_valid = text_trunk_validation_res.pass_validation if text_trunk_validation_res else None + is_text_chunk_valid = text_chunk_validation_res.pass_validation if text_chunk_validation_res else None is_seed_question_valid = question_validation_res.pass_validation if question_validation_res else None is_suggested_answer_valid = ( suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None @@ -31,9 +30,9 @@ def my_python_tool( failed_step = "" failed_reason = "" if not is_generation_success: - if is_text_trunk_valid is False: - failed_step = ValidateObj.TEXT_TRUNK - failed_reason = text_trunk_validation_res.reason + if is_text_chunk_valid is False: + failed_step = ValidateObj.TEXT_CHUNK + failed_reason = text_chunk_validation_res.reason elif is_seed_question_valid is False: failed_step = ValidateObj.QUESTION failed_reason = question_validation_res.reason @@ -42,29 +41,25 @@ def my_python_tool( failed_reason = suggested_answer_validation_res.reason return { - "question_type": question_type, - "text_trunk": text_trunk, - "text_meta": text_meta, - "generation_summary": { + # TODO: support more question types like multi-context etc. + # "question_type": question_type, + "text_chunk": text_chunk, + "validation_summary": { "success": is_generation_success, - "failed_step": failed_step, - "failed_reason": failed_reason, + "failed_step": failed_step }, - "generation_details": { - "text_trunk": { - "score": text_trunk_validation_res.score if text_trunk_validation_res else None, - "reason": text_trunk_validation_res.reason if text_trunk_validation_res else None, - "pass_validation": is_text_trunk_valid, + "validation_details": { + ValidateObj.TEXT_CHUNK: { + "score": text_chunk_validation_res.score if text_chunk_validation_res else None, + "success": is_text_chunk_valid, + "reason": text_chunk_validation_res.reason if text_chunk_validation_res else None, }, - "seed_question": { - "generated_question": generated_question, - "pass_validation": is_seed_question_valid, + ValidateObj.QUESTION: { + "success": is_seed_question_valid, "reason": question_validation_res.reason if question_validation_res else None, }, - # "test_question": {}, # placeholder for evolved questions like multi-context, reasoning, etc. - "suggested_answer": { - "generated_suggested_answer": generated_suggested_answer, - "pass_validation": is_suggested_answer_valid, + ValidateObj.SUGGESTED_ANSWER: { + "success": is_suggested_answer_valid, "reason": suggested_answer_validation_res.reason if suggested_answer_validation_res else None, }, }, diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py index 172bec2fb18..55a749e6604 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py @@ -7,13 +7,13 @@ @tool -def generate_seed_question( +def generate_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], model_or_deployment_name: str, generate_question_prompt: str, context: str = None, temperature: float = 1.0, - max_tokens: int = 512, + max_tokens: int = None, ): """ Generates a question based on the given context. @@ -21,7 +21,7 @@ def generate_seed_question( Returns: dict: The generated seed question. """ - # text trunk is not valid, just skip test data gen. + # text chunk is not valid, just skip test data gen. if not context: return "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index 41f2eb54f04..3a3878ee83f 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -14,7 +14,7 @@ def generate_suggested_answer( context: str, generate_suggested_answer_prompt: str, temperature: float = 1.0, - max_tokens: int = 512, + max_tokens: int = None, ): """ Generates a suggested answer based on the given prompts and context information. diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2 similarity index 95% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2 index 374d2ceb1d6..d9ffaf08523 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_trunk_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2 @@ -1,6 +1,6 @@ # system: -Given a text trunk from a document as context, perform the following tasks: +Given a text chunk from a document as context, perform the following tasks: 1. Exclude any references, acknowledgments, personal information, code snippets, or other non-essential elements from the original context. diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index f8ae83882ba..aeddfd6ea5d 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -2,8 +2,6 @@ import re from collections import namedtuple -import numpy as np -import numpy.testing as npt from numpy.random import default_rng from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @@ -13,15 +11,13 @@ class QuestionType: SIMPLE = "simple" - REASONING = "reasoning" - CONDITIONAL = "conditional" # MULTI_CONTEXT = "multi_context" class ValidateObj: - QUESTION = "question" - TEXT_TRUNK = "text_trunk" - SUGGESTED_ANSWER = "suggested_answer" + QUESTION = "validate_question" + TEXT_CHUNK = "validate_text_chunk" + SUGGESTED_ANSWER = "validate_suggested_answer" class ResponseFormat: @@ -31,7 +27,7 @@ class ResponseFormat: class ErrorMsg: INVALID_JSON_FORMAT = "Invalid json format. Response: {0}" - INVALID_TEXT_TRUNK = "Skipping generating seed question due to invalid text chunk: {0}" + INVALID_TEXT_CHUNK = "Skipping generating seed question due to invalid text chunk: {0}" INVALID_QUESTION = "Invalid seed question: {0}" INVALID_ANSWER = "Invalid answer: {0}" @@ -41,9 +37,10 @@ class ErrorMsg: def llm_call( - connection, model_or_deployment_name, prompt, response_format=ResponseFormat.TEXT, temperature=1.0, max_tokens=16 + connection, model_or_deployment_name, prompt, response_format=ResponseFormat.TEXT, temperature=1.0, max_tokens=None ): response_format = "json_object" if response_format.lower() == "json" else response_format + # avoid unnecessary jinja2 template re-rendering and potential error. prompt = f"{{% raw %}}{prompt}{{% endraw %}}" if isinstance(connection, AzureOpenAIConnection): return aoai_chat( @@ -75,9 +72,11 @@ def get_question_type(testset_distribution) -> str: def get_suggested_answer_validation_res( - connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, max_tokens: int + connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, max_tokens: int, + response_format: ResponseFormat = ResponseFormat.TEXT ): - rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens) + rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens, + response_format=response_format) return retrieve_verdict_and_print_reason( rsp=rsp, validate_obj_name=ValidateObj.SUGGESTED_ANSWER, validate_obj=suggested_answer ) @@ -96,7 +95,7 @@ def get_question_validation_res( return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) -def get_text_trunk_score( +def get_text_chunk_score( connection, model_or_deployment_name, prompt, @@ -114,7 +113,7 @@ def get_text_trunk_score( # Extract the verdict and reason score = data["score"].lower() reason = data["reason"] - print(f"Score {ValidateObj.TEXT_TRUNK}: {score}\nReason: {reason}") + print(f"Score {ValidateObj.TEXT_CHUNK}: {score}\nReason: {reason}") try: score_float = float(score) except ValueError: @@ -154,38 +153,3 @@ def _load_json_rsp(rsp: str): data = None return data - - -def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): - testset_distribution = { - QuestionType.SIMPLE: simple_ratio, - QuestionType.REASONING: reasoning_ratio, - QuestionType.CONDITIONAL: conditional_ratio, - } - npt.assert_almost_equal(1, sum(testset_distribution.values()), err_msg="Sum of distribution should be 1") - testset_distribution = dict(zip(testset_distribution.keys(), np.cumsum(list(testset_distribution.values())))) - return testset_distribution - - -def generate_question( - connection, - model_or_deployment_name, - question_type, - seed_question, - reasoning_prompt: str = None, - conditional_prompt: str = None, - temperature: float = None, - max_tokens: int = None, -): - if question_type == QuestionType.SIMPLE: - return seed_question - elif question_type == QuestionType.REASONING: - return llm_call( - connection, model_or_deployment_name, reasoning_prompt, temperature=temperature, max_tokens=max_tokens - ) - elif question_type == QuestionType.CONDITIONAL: - return llm_call( - connection, model_or_deployment_name, conditional_prompt, temperature=temperature, max_tokens=max_tokens - ) - else: - raise Exception("Invalid question type.") diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index 9473625cdae..db692353bf9 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -13,8 +13,8 @@ def validate_question( generated_question: str, validate_question_prompt: str, response_format: str = ResponseFormat.TEXT, - temperature: float = 1.0, - max_tokens: int = 512, + temperature: float = 0.2, + max_tokens: int = None, ): """ 1. Validates the given seed question. @@ -23,7 +23,7 @@ def validate_question( Returns: dict: The generated test question and its type. """ - # text trunk is not valid, seed question not generated. + # text chunk is not valid, seed question not generated. if not generated_question: return {"question": "", "question_type": "", "validation_res": None} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 0f61ad014b3..0fb7bb83f2e 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -16,7 +16,8 @@ def validate_suggested_answer( suggested_answer: str, validate_suggested_answer_prompt: str, temperature: float = 1.0, - max_tokens: int = 512, + max_tokens: int = None, + response_format: str = "text" ): """ 1. Validates the given suggested answer. @@ -34,6 +35,7 @@ def validate_suggested_answer( suggested_answer, temperature, max_tokens, + response_format ) is_valid_gt = validation_res.pass_validation failed_reason = "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py similarity index 56% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py rename to examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py index 894fbef3324..4cb652c7f4f 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_trunk.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py @@ -1,39 +1,39 @@ from typing import Union -from utils import ErrorMsg, ResponseFormat, get_text_trunk_score +from utils import ErrorMsg, ResponseFormat, get_text_chunk_score from promptflow import tool from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool -def validate_text_trunk( +def validate_text_chunk( connection: Union[OpenAIConnection, AzureOpenAIConnection], model_or_deployment_name: str, - score_text_trunk_prompt: str, + score_text_chunk_prompt: str, score_threshold: float, context: str = None, response_format: str = ResponseFormat.TEXT, temperature: float = 1.0, - max_tokens: int = 512, + max_tokens: int = None, ): """ Validates the given text chunk. If the validation fails, return an empty context and the validation result. Returns: - dict: Text trunk context and its validation result. + dict: Text chunk context and its validation result. """ - text_trunk_score_res = get_text_trunk_score( + text_chunk_score_res = get_text_chunk_score( connection, model_or_deployment_name, - score_text_trunk_prompt, + score_text_chunk_prompt, response_format, score_threshold, temperature, max_tokens, ) - if not text_trunk_score_res.pass_validation: - print(ErrorMsg.INVALID_TEXT_TRUNK.format(context)) - return {"context": "", "validation_res": text_trunk_score_res} + if not text_chunk_score_res.pass_validation: + print(ErrorMsg.INVALID_TEXT_CHUNK.format(context)) + return {"context": "", "validation_res": text_chunk_score_res} - return {"context": context, "validation_res": text_trunk_score_res} + return {"context": context, "validation_res": text_chunk_score_res} diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 65c53bc521a..8b743717f70 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,56 +1,58 @@ import json import os +import time from datetime import datetime from pathlib import Path import configargparse -from promptflow import PFClient from promptflow._utils.logger_utils import get_logger -from promptflow.entities import Run CONFIG_FILE = (Path(__file__).parents[1] / "config.ini").resolve() # in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) -from common import clean_data_and_save, count_non_blank_lines, split_document # noqa: E402 -from constants import TEXT_CHUNK # noqa: E402 +from common import clean_data, count_non_blank_lines, split_document, print_progress # noqa: E402 +from constants import TEXT_CHUNK, DETAILS_FILE_NAME # noqa: E402 logger = get_logger("data.gen") def batch_run_flow( - pf: PFClient, flow_folder: str, flow_input_data: str, flow_batch_run_size: int, ): logger.info("Step 2: Start to batch run 'generate_test_data_flow'...") - base_run = pf.run( - flow=flow_folder, - data=flow_input_data, - stream=True, - environment_variables={ - "PF_WORKER_COUNT": str(flow_batch_run_size), - "PF_BATCH_METHOD": "spawn", - }, - column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, - debug=True, - ) - logger.info("Batch run is completed.") - return base_run - - -def get_batch_run_output(pf: PFClient, base_run: Run): - logger.info(f"Start to get batch run {base_run.name} details.") - details = pf.get_details(base_run, all_results=True) - question = details["outputs.question"].tolist() - suggested_answer = details["outputs.suggested_answer"].tolist() - debug_info = details["outputs.debug_info"].tolist() + import subprocess + + run_name = f"test_data_gen_{datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}" + # TODO: replace the separate process to submit batch run with batch run async method when it's available. + cmd = f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " \ + f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " \ + f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}'" + process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + logger.info(f"Submit batch run successfully. process id {process.pid}. Please wait for the batch run to complete...") + return run_name + + +def get_batch_run_output(output_path: Path): + logger.info(f"Reading batch run output from '{output_path}'.") + # wait for the output file to be created + start_time = time.time() + while not Path(output_path).is_file(): + time.sleep(1) + # if the log file is not created within 5 minutes, raise an error + if time.time() - start_time > 300: + raise Exception(f"Output jsonl file '{output_path}' is not created within 5 minutes.") + + with open(output_path, 'r') as f: + output_lines = list(map(json.loads, f)) + return [ - {"question": q, "suggested_answer": g, "debug_info": d} - for q, g, d in zip(question, suggested_answer, debug_info) + {"question": line["question"], "suggested_answer": line["suggested_answer"], "debug_info": line["debug_info"]} + for line in output_lines ] @@ -64,31 +66,30 @@ def run_local( should_skip_split, ): text_chunks_path = document_nodes_file - inner_folder = os.path.join(output_folder, datetime.now().strftime("%b-%d-%Y-%H-%M-%S")) - if not os.path.isdir(inner_folder): - os.makedirs(inner_folder) + output_folder = Path(output_folder) / datetime.now().strftime("%b-%d-%Y-%H-%M-%S") + if not Path(output_folder).is_dir(): + Path(output_folder).mkdir(parents=True, exist_ok=True) if not should_skip_split: - text_chunks_path = split_document(document_chunk_size, documents_folder, inner_folder) + text_chunks_path = split_document(document_chunk_size, documents_folder, output_folder) - pf = PFClient() - batch_run = batch_run_flow( - pf, + run_name = batch_run_flow( flow_folder, text_chunks_path, flow_batch_run_size, ) - - test_data_set = get_batch_run_output(pf, batch_run) - + run_folder_path = Path.home() / f".promptflow/.runs/{run_name}" + print_progress(run_folder_path / "logs.txt") + test_data_set = get_batch_run_output(run_folder_path / "outputs.jsonl") # Store intermedian batch run output results jsonl_str = "\n".join(map(json.dumps, test_data_set)) - intermedian_batch_run_res = os.path.join(inner_folder, "test-data-gen-details.jsonl") - with open(intermedian_batch_run_res, "wt") as text_file: + batch_run_details_file = Path(output_folder) / DETAILS_FILE_NAME + with open(batch_run_details_file, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - clean_data_output = os.path.join(inner_folder, "test-data.jsonl") - clean_data_and_save(test_data_set, clean_data_output) + clean_data_output = Path(output_folder) / "test-data.jsonl" + clean_data(test_data_set, clean_data_output) + logger.info(f"More debug info of test data generation can be found in '{batch_run_details_file}'.") def run_cloud( @@ -144,7 +145,7 @@ def gen_test_data_pipeline( run_invocation_time=600, allowed_failed_count=-1, ): - from components import clean_data_and_save_component, split_document_component + from components import clean_data_component, split_document_component data = ( data_input @@ -168,7 +169,7 @@ def gen_test_data_pipeline( flow_node.mini_batch_error_threshold = allowed_failed_count # Should use `mount` mode to ensure PRS complete merge output lines. flow_node.outputs.flow_outputs.mode = "mount" - clean_data_and_save_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output + clean_data_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) diff --git a/examples/gen_test_data/gen_test_data/utils/__init__.py b/examples/gen_test_data/gen_test_data/utils/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/gen_test_data/gen_test_data/utils/analyze_data.py b/examples/gen_test_data/gen_test_data/utils/analyze_data.py deleted file mode 100644 index 21cb0acbd6c..00000000000 --- a/examples/gen_test_data/gen_test_data/utils/analyze_data.py +++ /dev/null @@ -1,50 +0,0 @@ -import json -from argparse import ArgumentParser -from pathlib import Path - - -def analyze_batch_run_res(file_path): - gen_success_count = 0 - gen_failure_count = 0 - run_failed_count = 0 - gen_failure_steps = {} - gen_failure_reasons = {} - - with open(file_path, "r") as f: - for line in f: - data = json.loads(line) - - if data["debug_info"] == "(Failed)": - run_failed_count += 1 - continue - - if data["debug_info"]["generation_summary"]["success"]: - gen_success_count += 1 - else: - gen_failure_count += 1 - failed_step = data["debug_info"]["generation_summary"]["failed_step"] - failed_reason = data["debug_info"]["generation_summary"]["failed_reason"] - - if failed_step in gen_failure_steps: - gen_failure_steps[failed_step] += 1 - gen_failure_reasons[failed_step].append(failed_reason) - else: - gen_failure_steps[failed_step] = 1 - gen_failure_reasons[failed_step] = [failed_reason] - - print(f"Gen success count: {gen_success_count}") - print(f"Gen failure count: {gen_failure_count}") - print(f"Run failure count: {run_failed_count}") - print("Gen failures by step:") - for step, count in gen_failure_steps.items(): - print(f"{step}: {count}") - print("**Gen failures by reason:") - for step, reasons in gen_failure_reasons.items(): - print(f"{step}: {reasons}") - - -if __name__ == "__main__": - parser = ArgumentParser() - parser.add_argument("-f", "--jsonl_file", type=Path, required=True) - args = parser.parse_args() - analyze_batch_run_res(args.jsonl_file) From c52f285b7b99d547ac5c0eff8f2345fc6dc33ace Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Sun, 4 Feb 2024 11:43:32 +0800 Subject: [PATCH 049/112] Support relative path (#1938) ![image](https://github.com/microsoft/promptflow/assets/46446115/6bd9acc0-2886-47e3-b583-f69b489e45df) --------- Co-authored-by: yalu4 --- examples/gen_test_data/config.ini.example | 10 ++-- .../gen_test_data/gen_test_data/common.py | 40 ++++++++++---- examples/gen_test_data/gen_test_data/run.py | 52 ++++++++++++------- 3 files changed, 67 insertions(+), 35 deletions(-) diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index 234b298f9ed..fa319fea1ca 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -5,19 +5,19 @@ ; The COMMON section provides common values for all other sections. ; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. ; However, if you wish to bypass the document split process, simply provide the 'document_node_file', which is a JSONL file. -; When all these parameters are configured, the system will primarily use the 'document_node_file' -documents_folder = "" +; When all these parameters are configured, the system will primarily use the 'document_node_file'. +documents_folder = "" document_chunk_size = 1024 -document_nodes_file = "" +document_nodes_file = "" ; Test data gen flow configs -flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry +flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry connection_name = "" [LOCAL] ; This section is for local test data generation related configuration. -output_folder = "" +output_folder = "" flow_batch_run_size = 4 diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 623827efdda..4e6a94de152 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -1,11 +1,12 @@ import json -import sys import re +import sys import time import typing as t from pathlib import Path from constants import DOCUMENT_NODE, TEXT_CHUNK + from promptflow._utils.logger_utils import get_logger @@ -24,8 +25,11 @@ def split_document(chunk_size, documents_folder, document_node_output): logger.info("Step 1: Start to split documents to document nodes...") # count the number of files in documents_folder, including subfolders. num_files = sum(1 for _ in Path(documents_folder).rglob("*") if _.is_file()) - logger.info(f"Found {num_files} files in the documents folder '{documents_folder}'. Using chunk size: {chunk_size} to split.") - # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. + logger.info( + f"Found {num_files} files in the documents folder '{documents_folder}'. " + f"Using chunk size: {chunk_size} to split." + ) + # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. # noqa: E501 # TODO: improve on top of `SimpleDirectoryReader` with a better chunking algorithm. chunks = SimpleDirectoryReader(documents_folder, recursive=True, encoding="utf-8").load_data() # Convert documents into nodes @@ -50,7 +54,7 @@ def clean_data(test_data_set: list, test_data_output_path: str): for test_data in test_data_set: if test_data and all( - val and val != "(Failed)" for key, val in test_data.items() if key.lower() != "line_number" + val and val != "(Failed)" for key, val in test_data.items() if key.lower() != "line_number" ): data_line = {"question": test_data["question"], "suggested_answer": test_data["suggested_answer"]} cleaned_data.append(data_line) @@ -61,12 +65,14 @@ def clean_data(test_data_set: list, test_data_output_path: str): # TODO: aggregate invalid data root cause and count, and log it. # log debug info path. - logger.info(f"Removed {len(test_data_set) - len(cleaned_data)} invalid test data. " - f"Saved {len(cleaned_data)} valid test data to '{test_data_output_path}'.") + logger.info( + f"Removed {len(test_data_set) - len(cleaned_data)} invalid test data. " + f"Saved {len(cleaned_data)} valid test data to '{test_data_output_path}'." + ) def count_non_blank_lines(file_path): - with open(file_path, 'r') as file: + with open(file_path, "r") as file: lines = file.readlines() non_blank_lines = len([line for line in lines if line.strip()]) @@ -87,7 +93,7 @@ def print_progress(log_file_path: str): try: last_data_time = time.time() - with open(log_file_path, 'r') as f: + with open(log_file_path, "r") as f: while True: line = f.readline().strip() if line: @@ -95,7 +101,7 @@ def print_progress(log_file_path: str): match = log_pattern.match(line) if not match: continue - + sys.stdout.write("\r" + line) # \r will move the cursor back to the beginning of the line sys.stdout.flush() # flush the buffer to ensure the log is displayed immediately finished, total = map(int, match.groups()) @@ -103,10 +109,24 @@ def print_progress(log_file_path: str): logger.info("Batch run is completed.") break elif time.time() - last_data_time > 300: - logger.info("No new log line received for 5 minutes. Stop reading. See the log file for more details.") + logger.info( + "No new log line received for 5 minutes. Stop reading. See the log file for more details." + ) break # Stop reading else: time.sleep(1) # wait for 1 second if no new line is available except KeyboardInterrupt: sys.stdout.write("\n") # ensure to start on a new line when the user interrupts sys.stdout.flush() + + +def convert_to_abs_path(file_path: str) -> str: + if not file_path: + return file_path + + path = Path(file_path) + if path.is_absolute(): + return str(path) + else: + abs = str(path.resolve()) + return abs diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 8b743717f70..b8ecbac77a4 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -13,8 +13,8 @@ # in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) -from common import clean_data, count_non_blank_lines, split_document, print_progress # noqa: E402 -from constants import TEXT_CHUNK, DETAILS_FILE_NAME # noqa: E402 +from common import clean_data, convert_to_abs_path, count_non_blank_lines, print_progress, split_document # noqa: E402 +from constants import DETAILS_FILE_NAME, TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") @@ -29,11 +29,15 @@ def batch_run_flow( run_name = f"test_data_gen_{datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}" # TODO: replace the separate process to submit batch run with batch run async method when it's available. - cmd = f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " \ - f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " \ - f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}'" + cmd = ( + f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " + f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " + f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}'" + ) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - logger.info(f"Submit batch run successfully. process id {process.pid}. Please wait for the batch run to complete...") + logger.info( + f"Submit batch run successfully. process id {process.pid}. Please wait for the batch run to complete..." + ) return run_name @@ -47,9 +51,9 @@ def get_batch_run_output(output_path: Path): if time.time() - start_time > 300: raise Exception(f"Output jsonl file '{output_path}' is not created within 5 minutes.") - with open(output_path, 'r') as f: + with open(output_path, "r") as f: output_lines = list(map(json.loads, f)) - + return [ {"question": line["question"], "suggested_answer": line["suggested_answer"], "debug_info": line["debug_info"]} for line in output_lines @@ -250,10 +254,18 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str args = parser.parse_args() should_skip_split_documents = False - if args.document_nodes_file and Path(args.document_nodes_file).is_file(): + document_nodes_file = convert_to_abs_path(args.document_nodes_file) + documents_folder = convert_to_abs_path(args.documents_folder) + flow_folder = convert_to_abs_path(args.flow_folder) + output_folder = convert_to_abs_path(args.output_folder) + + if document_nodes_file and Path(document_nodes_file).is_file(): should_skip_split_documents = True - elif not args.documents_folder or not Path(args.documents_folder).is_dir(): - parser.error("Either 'documents_folder' or 'document_nodes_file' should be specified correctly.") + elif not documents_folder or not Path(documents_folder).is_dir(): + parser.error( + "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" + f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" + ) if args.cloud: logger.info("Start to generate test data at cloud...") @@ -263,16 +275,16 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str if should_skip_split_documents: logger.info( "Skip step 1 'Split documents to document nodes' as received document nodes from " - f"input file '{args.document_nodes_file}'." + f"input file path '{document_nodes_file}'." ) - logger.info(f"Collected {count_non_blank_lines(args.document_nodes_file)} document nodes.") + logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") if args.cloud: run_cloud( - args.documents_folder, + documents_folder, args.document_chunk_size, - args.document_nodes_file, - args.flow_folder, + document_nodes_file, + flow_folder, args.subscription_id, args.resource_group, args.workspace_name, @@ -287,11 +299,11 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str ) else: run_local( - args.documents_folder, + documents_folder, args.document_chunk_size, - args.document_nodes_file, - args.flow_folder, + document_nodes_file, + flow_folder, args.flow_batch_run_size, - args.output_folder, + output_folder, should_skip_split_documents, ) From 5c2318e311a229cc3aed8d2ef15f98c521bc568b Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:06:03 +0800 Subject: [PATCH 050/112] [data gen] fix doc links, progress bar, hide max_tokens (#1941) - fix broken doc links. - progress bar. - hide max_tokens from python tool ![image](https://github.com/microsoft/promptflow/assets/49483542/46479e92-774a-43c0-bbd3-b7f34829718d) --- docs/how-to-guides/generate-test-data.md | 2 +- .../gen_test_data/gen_test_data/common.py | 28 ++++++++++++------- .../generate_question.py | 5 ++-- .../generate_suggested_answer.py | 4 +-- .../generate_test_data_flow/utils.py | 8 +++--- .../validate_question.py | 2 -- .../validate_suggested_answer.py | 6 ++-- .../validate_text_chunk.py | 4 +-- examples/gen_test_data/gen_test_data/run.py | 2 +- 9 files changed, 30 insertions(+), 31 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 14979bfc346..fa267c20764 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -30,7 +30,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 4. [Create connections](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) 5. Prepare config.ini - - Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. + - Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. - Run command to copy [`config.ini.example`](../../examples/gen_test_data/config.ini.example). ``` cp config.ini.example config.ini diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 4e6a94de152..acdb61c4e83 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -80,8 +80,9 @@ def count_non_blank_lines(file_path): def print_progress(log_file_path: str): + from tqdm import tqdm logger = get_logger("data.gen") - logger.info(f"Showing progress log, or you can click '{log_file_path}' and see detailed batch run log...") + logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") # wait for the log file to be created start_time = time.time() @@ -91,6 +92,7 @@ def print_progress(log_file_path: str): if time.time() - start_time > 300: raise Exception(f"Log file '{log_file_path}' is not created within 5 minutes.") + pbar = None try: last_data_time = time.time() with open(log_file_path, "r") as f: @@ -102,22 +104,28 @@ def print_progress(log_file_path: str): if not match: continue - sys.stdout.write("\r" + line) # \r will move the cursor back to the beginning of the line - sys.stdout.flush() # flush the buffer to ensure the log is displayed immediately finished, total = map(int, match.groups()) + if pbar is None: + pbar = tqdm(total=total, desc="Processing", file=sys.stdout) + pbar.update(finished - pbar.n) + if finished == total: + pbar.close() logger.info("Batch run is completed.") + break elif time.time() - last_data_time > 300: - logger.info( - "No new log line received for 5 minutes. Stop reading. See the log file for more details." - ) - break # Stop reading + logger.info("No new log line received for 5 minutes. Stop reading. " + f"See the log file '{log_file_path}' for more details.") + break else: time.sleep(1) # wait for 1 second if no new line is available - except KeyboardInterrupt: - sys.stdout.write("\n") # ensure to start on a new line when the user interrupts - sys.stdout.flush() + except Exception as e: + raise Exception(f"Error occurred while printing batch run progress {e}. " + f"See the log file '{log_file_path}' for more details.") + finally: + if pbar: + pbar.close() def convert_to_abs_path(file_path: str) -> str: diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py index 55a749e6604..6cddc4f6b55 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py @@ -12,8 +12,7 @@ def generate_question( model_or_deployment_name: str, generate_question_prompt: str, context: str = None, - temperature: float = 1.0, - max_tokens: int = None, + temperature: float = 0.2 ): """ Generates a question based on the given context. @@ -26,6 +25,6 @@ def generate_question( return "" seed_question = llm_call( - connection, model_or_deployment_name, generate_question_prompt, temperature=temperature, max_tokens=max_tokens + connection, model_or_deployment_name, generate_question_prompt, temperature=temperature ) return seed_question diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index 3a3878ee83f..ef738d04b9b 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -13,8 +13,7 @@ def generate_suggested_answer( question: str, context: str, generate_suggested_answer_prompt: str, - temperature: float = 1.0, - max_tokens: int = None, + temperature: float = 0.2 ): """ Generates a suggested answer based on the given prompts and context information. @@ -28,7 +27,6 @@ def generate_suggested_answer( model_or_deployment_name, generate_suggested_answer_prompt, temperature=temperature, - max_tokens=max_tokens, ) else: return "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index aeddfd6ea5d..f38ace88f24 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -72,8 +72,8 @@ def get_question_type(testset_distribution) -> str: def get_suggested_answer_validation_res( - connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, max_tokens: int, - response_format: ResponseFormat = ResponseFormat.TEXT + connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, + max_tokens: int=None, response_format: ResponseFormat = ResponseFormat.TEXT ): rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens, response_format=response_format) @@ -89,7 +89,7 @@ def get_question_validation_res( question: str, response_format: ResponseFormat, temperature: float, - max_tokens: int, + max_tokens: int = None, ): rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) @@ -102,7 +102,7 @@ def get_text_chunk_score( response_format: ResponseFormat, score_threshold: float, temperature: float, - max_tokens: int, + max_tokens: int = None, ): rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) data = _load_json_rsp(rsp) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index db692353bf9..3442f23581a 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -14,7 +14,6 @@ def validate_question( validate_question_prompt: str, response_format: str = ResponseFormat.TEXT, temperature: float = 0.2, - max_tokens: int = None, ): """ 1. Validates the given seed question. @@ -34,7 +33,6 @@ def validate_question( generated_question, response_format, temperature, - max_tokens, ) is_valid_seed_question = validation_res.pass_validation question = "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 0fb7bb83f2e..491f2327618 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -15,8 +15,7 @@ def validate_suggested_answer( model_or_deployment_name: str, suggested_answer: str, validate_suggested_answer_prompt: str, - temperature: float = 1.0, - max_tokens: int = None, + temperature: float = 0.2, response_format: str = "text" ): """ @@ -34,8 +33,7 @@ def validate_suggested_answer( validate_suggested_answer_prompt, suggested_answer, temperature, - max_tokens, - response_format + response_format=response_format ) is_valid_gt = validation_res.pass_validation failed_reason = "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py index 4cb652c7f4f..b724a7686e4 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py @@ -14,8 +14,7 @@ def validate_text_chunk( score_threshold: float, context: str = None, response_format: str = ResponseFormat.TEXT, - temperature: float = 1.0, - max_tokens: int = None, + temperature: float = 0.2, ): """ Validates the given text chunk. If the validation fails, return an empty context and the validation result. @@ -30,7 +29,6 @@ def validate_text_chunk( response_format, score_threshold, temperature, - max_tokens, ) if not text_chunk_score_res.pass_validation: print(ErrorMsg.INVALID_TEXT_CHUNK.format(context)) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index b8ecbac77a4..913cca3b196 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -51,7 +51,7 @@ def get_batch_run_output(output_path: Path): if time.time() - start_time > 300: raise Exception(f"Output jsonl file '{output_path}' is not created within 5 minutes.") - with open(output_path, "r") as f: + with open(output_path, "r", encoding='utf-8') as f: output_lines = list(map(json.loads, f)) return [ From 5c169433623cbcced589218830ece762c84b9489 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:05:22 +0800 Subject: [PATCH 051/112] Override node inputs (#1937) # Description (https://ml.azure.com/runs/great_house_1c5cvbzcsq?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47#) https://ml.azure.com/runs/loving_bean_2q07s6qs6x?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- .gitignore | 4 + examples/gen_test_data/config.ini.example | 5 +- .../gen_test_data/gen_test_data/common.py | 32 +++ .../generate_test_data_flow/flow.dag.yaml | 5 + examples/gen_test_data/gen_test_data/run.py | 196 +++++++++--------- 5 files changed, 147 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 85b40811f1a..f74aeafac1f 100644 --- a/.gitignore +++ b/.gitignore @@ -171,6 +171,10 @@ connection.json .azureml # dummy custom tool package example hello-world-proj/** +# temp gen test data folder +examples/gen_test_data/gen_test_data/*_temp +# gen test data config +examples/gen_test_data/config.ini # secrets **/connections.json diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index fa319fea1ca..7eff5bb4f55 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -13,7 +13,10 @@ document_nodes_file = "" ; Test data gen flow configs flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry connection_name = "" - +; Override some node inputs, for example, {"node_1": {"input_1": "value", "input_2": "value"}, "node_2":{"input_1": "value", "input_2": "value"}} +; Ensure the node name and the input name exist in flag.dag.yaml +; If not fill in "node_inputs_override", we will use the values in flow.dag.yaml +node_inputs_override = {"validate_text_chunk": {"connection": "", "model_or_deployment_name": ""}, "generate_question": {"connection": "", "model_or_deployment_name": ""}, "validate_question": {"connection": "", "model_or_deployment_name": ""}, "generate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}, "validate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}} [LOCAL] ; This section is for local test data generation related configuration. diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index acdb61c4e83..14fffad0dee 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -1,4 +1,5 @@ import json +import shutil import re import sys import time @@ -8,6 +9,7 @@ from constants import DOCUMENT_NODE, TEXT_CHUNK from promptflow._utils.logger_utils import get_logger +from promptflow._utils.yaml_utils import dump_yaml, load_yaml def split_document(chunk_size, documents_folder, document_node_output): @@ -128,6 +130,36 @@ def print_progress(log_file_path: str): pbar.close() +def copy_flow_folder_and_set_node_inputs(copied_folder, flow_folder, node_inputs_override): + logger = get_logger("node_inputs_override") + logger.info("Overriding the values of node inputs in flag.dag.yaml...") + if not (Path(flow_folder) / "flow.dag.yaml").is_file(): + raise ValueError(f"The file 'flag.dag.yaml' does not exist in {flow_folder}.") + + if Path(copied_folder).exists(): + shutil.rmtree(copied_folder) + shutil.copytree(flow_folder, copied_folder) + + with open(Path(copied_folder) / "flow.dag.yaml", "r", encoding="utf-8") as f: + data = load_yaml(f) + + if node_inputs_override and len(node_inputs_override) > 0: + # Update the YAML data according to the config dict + for node_name, inputs in node_inputs_override.items(): + node = next((node for node in data['nodes'] if node['name'] == node_name), None) + if node is None: + raise ValueError(f"Node '{node_name}' not found in the flag.dag.yaml.") + for input_name, input_value in inputs.items(): + if input_name not in node['inputs']: + raise ValueError(f"Input '{input_name}' not found in node '{node_name}'.") + + if not (input_value.startswith('<') and input_value.endswith('>')): + node['inputs'][input_name] = input_value + + with open(Path(copied_folder) / "flow.dag.yaml", 'w', encoding="utf-8") as f: + dump_yaml(data, f) + + def convert_to_abs_path(file_path: str) -> str: if not file_path: return file_path diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 36a3baa9acf..608f22948a8 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -59,6 +59,7 @@ nodes: type: code path: generate_question.py inputs: + connection: "" model_or_deployment_name: "" context: ${validate_text_chunk.output.context} temperature: 0.2 @@ -70,6 +71,7 @@ nodes: type: code path: validate_question.py inputs: + connection: "" model_or_deployment_name: "" temperature: 0.2 generated_question: ${generate_question.output} @@ -81,6 +83,7 @@ nodes: type: code path: generate_suggested_answer.py inputs: + connection: "" context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} question: ${validate_question.output.question} @@ -111,6 +114,7 @@ nodes: type: code path: validate_suggested_answer.py inputs: + connection: "" model_or_deployment_name: "" suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} @@ -121,6 +125,7 @@ nodes: type: code path: validate_text_chunk.py inputs: + connection: "" score_text_chunk_prompt: ${score_text_chunk_prompt.output} context: ${inputs.text_chunk} score_threshold: 4 diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 913cca3b196..d939f37b062 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,5 +1,6 @@ import json import os +import shutil import time from datetime import datetime from pathlib import Path @@ -13,8 +14,10 @@ # in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) -from common import clean_data, convert_to_abs_path, count_non_blank_lines, print_progress, split_document # noqa: E402 -from constants import DETAILS_FILE_NAME, TEXT_CHUNK # noqa: E402 +from common import clean_data, count_non_blank_lines, \ + split_document, copy_flow_folder_and_set_node_inputs, \ + print_progress, convert_to_abs_path # noqa: E402 +from constants import TEXT_CHUNK, DETAILS_FILE_NAME # noqa: E402 logger = get_logger("data.gen") @@ -61,13 +64,13 @@ def get_batch_run_output(output_path: Path): def run_local( - documents_folder, - document_chunk_size, - document_nodes_file, - flow_folder, - flow_batch_run_size, - output_folder, - should_skip_split, + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + flow_batch_run_size, + output_folder, + should_skip_split, ): text_chunks_path = document_nodes_file output_folder = Path(output_folder) / datetime.now().strftime("%b-%d-%Y-%H-%M-%S") @@ -80,8 +83,9 @@ def run_local( run_name = batch_run_flow( flow_folder, text_chunks_path, - flow_batch_run_size, + flow_batch_run_size ) + run_folder_path = Path.home() / f".promptflow/.runs/{run_name}" print_progress(run_folder_path / "logs.txt") test_data_set = get_batch_run_output(run_folder_path / "outputs.jsonl") @@ -97,21 +101,21 @@ def run_local( def run_cloud( - documents_folder, - document_chunk_size, - document_nodes_file, - flow_folder, - subscription_id, - resource_group, - workspace_name, - aml_cluster, - prs_instance_count, - prs_mini_batch_size, - prs_max_concurrency_per_instance, - prs_max_retry_count, - prs_run_invocation_time, - prs_allowed_failed_count, - should_skip_split, + documents_folder, + document_chunk_size, + document_nodes_file, + flow_folder, + subscription_id, + resource_group, + workspace_name, + aml_cluster, + prs_instance_count, + prs_mini_batch_size, + prs_max_concurrency_per_instance, + prs_max_retry_count, + prs_run_invocation_time, + prs_allowed_failed_count, + should_skip_split, ): # lazy import azure dependencies try: @@ -138,16 +142,16 @@ def run_cloud( ] ) def gen_test_data_pipeline( - data_input: V2Input, - flow_yml_path: str, - should_skip_doc_split: bool, - chunk_size=1024, - instance_count=1, - mini_batch_size=1, - max_concurrency_per_instance=2, - max_retry_count=3, - run_invocation_time=600, - allowed_failed_count=-1, + data_input: V2Input, + flow_yml_path: str, + should_skip_doc_split: bool, + chunk_size=1024, + instance_count=1, + mini_batch_size=1, + max_concurrency_per_instance=2, + max_retry_count=3, + run_invocation_time=600, + allowed_failed_count=-1, ): from components import clean_data_component, split_document_component @@ -160,11 +164,7 @@ def gen_test_data_pipeline( ) flow_node = load_component(flow_yml_path)( data=data, - text_chunk="${data.text_chunk}", - # connections={ - # key: {"connection": value["connection"].format(connection_name=connection_name)} - # for key, value in CONNECTIONS_TEMPLATE.items() - # }, + text_chunk="${data.text_chunk}" ) flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance @@ -234,6 +234,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str type=int, help="Test data generation flow batch run size, default is 16", ) + parser.add_argument("--node_inputs_override", type=json.loads, help="The inputs need to override") # Configs for local parser.add_argument("--output_folder", type=str, help="Output folder path.") # Configs for cloud @@ -252,58 +253,65 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str "--prs_allowed_failed_count", type=int, help="Number of failed mini batches that could be ignored" ) args = parser.parse_args() + copied_flow_folder = args.flow_folder + "_" + time.strftime("%b-%d-%Y-%H-%M-%S") + "_temp" - should_skip_split_documents = False - document_nodes_file = convert_to_abs_path(args.document_nodes_file) - documents_folder = convert_to_abs_path(args.documents_folder) - flow_folder = convert_to_abs_path(args.flow_folder) - output_folder = convert_to_abs_path(args.output_folder) - - if document_nodes_file and Path(document_nodes_file).is_file(): - should_skip_split_documents = True - elif not documents_folder or not Path(documents_folder).is_dir(): - parser.error( - "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" - f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" - ) - - if args.cloud: - logger.info("Start to generate test data at cloud...") - else: - logger.info("Start to generate test data at local...") - - if should_skip_split_documents: - logger.info( - "Skip step 1 'Split documents to document nodes' as received document nodes from " - f"input file path '{document_nodes_file}'." - ) - logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") - - if args.cloud: - run_cloud( - documents_folder, - args.document_chunk_size, - document_nodes_file, - flow_folder, - args.subscription_id, - args.resource_group, - args.workspace_name, - args.aml_cluster, - args.prs_instance_count, - args.prs_mini_batch_size, - args.prs_max_concurrency_per_instance, - args.prs_max_retry_count, - args.prs_run_invocation_time, - args.prs_allowed_failed_count, - should_skip_split_documents, - ) - else: - run_local( - documents_folder, - args.document_chunk_size, - document_nodes_file, - flow_folder, - args.flow_batch_run_size, - output_folder, - should_skip_split_documents, - ) + try: + should_skip_split_documents = False + document_nodes_file = convert_to_abs_path(args.document_nodes_file) + documents_folder = convert_to_abs_path(args.documents_folder) + flow_folder = convert_to_abs_path(args.flow_folder) + output_folder = convert_to_abs_path(args.output_folder) + + if document_nodes_file and Path(document_nodes_file).is_file(): + should_skip_split_documents = True + elif not documents_folder or not Path(documents_folder).is_dir(): + parser.error( + "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" + f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" + ) + + if args.cloud: + logger.info("Start to generate test data at cloud...") + else: + logger.info("Start to generate test data at local...") + + if should_skip_split_documents: + logger.info( + "Skip step 1 'Split documents to document nodes' as received document nodes from " + f"input file path '{document_nodes_file}'." + ) + logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") + + copy_flow_folder_and_set_node_inputs(copied_flow_folder, args.flow_folder, args.node_inputs_override) + + if args.cloud: + run_cloud( + documents_folder, + args.document_chunk_size, + document_nodes_file, + copied_flow_folder, + args.subscription_id, + args.resource_group, + args.workspace_name, + args.aml_cluster, + args.prs_instance_count, + args.prs_mini_batch_size, + args.prs_max_concurrency_per_instance, + args.prs_max_retry_count, + args.prs_run_invocation_time, + args.prs_allowed_failed_count, + should_skip_split_documents, + ) + else: + run_local( + documents_folder, + args.document_chunk_size, + document_nodes_file, + copied_flow_folder, + args.flow_batch_run_size, + output_folder, + should_skip_split_documents, + ) + finally: + if os.path.exists(copied_flow_folder): + shutil.rmtree(copied_flow_folder) From 08899513788feb7fc5893a0bb82cd1e999123244 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:20:46 +0800 Subject: [PATCH 052/112] Update config.ini.example --- examples/gen_test_data/config.ini.example | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index 7eff5bb4f55..ea2ca5d12c5 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -12,7 +12,6 @@ document_nodes_file = "" ; Test data gen flow configs flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry -connection_name = "" ; Override some node inputs, for example, {"node_1": {"input_1": "value", "input_2": "value"}, "node_2":{"input_1": "value", "input_2": "value"}} ; Ensure the node name and the input name exist in flag.dag.yaml ; If not fill in "node_inputs_override", we will use the values in flow.dag.yaml From cc0d87659348e56db58d4b9c41abc35d30b9d4b5 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:59:05 +0800 Subject: [PATCH 053/112] Fix version and invalid file path (#1949) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. Co-authored-by: yalu4 --- .../gen_test_data/gen_test_data/common.py | 29 ++++++++++++------- examples/gen_test_data/requirements.txt | 2 +- examples/gen_test_data/requirements_cloud.txt | 2 +- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 14fffad0dee..f7493c710e8 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -1,6 +1,6 @@ import json -import shutil import re +import shutil import sys import time import typing as t @@ -83,6 +83,7 @@ def count_non_blank_lines(file_path): def print_progress(log_file_path: str): from tqdm import tqdm + logger = get_logger("data.gen") logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") @@ -117,14 +118,18 @@ def print_progress(log_file_path: str): break elif time.time() - last_data_time > 300: - logger.info("No new log line received for 5 minutes. Stop reading. " - f"See the log file '{log_file_path}' for more details.") + logger.info( + "No new log line received for 5 minutes. Stop reading. " + f"See the log file '{log_file_path}' for more details." + ) break else: time.sleep(1) # wait for 1 second if no new line is available except Exception as e: - raise Exception(f"Error occurred while printing batch run progress {e}. " - f"See the log file '{log_file_path}' for more details.") + raise Exception( + f"Error occurred while printing batch run progress {e}. " + f"See the log file '{log_file_path}' for more details." + ) finally: if pbar: pbar.close() @@ -146,17 +151,17 @@ def copy_flow_folder_and_set_node_inputs(copied_folder, flow_folder, node_inputs if node_inputs_override and len(node_inputs_override) > 0: # Update the YAML data according to the config dict for node_name, inputs in node_inputs_override.items(): - node = next((node for node in data['nodes'] if node['name'] == node_name), None) + node = next((node for node in data["nodes"] if node["name"] == node_name), None) if node is None: raise ValueError(f"Node '{node_name}' not found in the flag.dag.yaml.") for input_name, input_value in inputs.items(): - if input_name not in node['inputs']: + if input_name not in node["inputs"]: raise ValueError(f"Input '{input_name}' not found in node '{node_name}'.") - if not (input_value.startswith('<') and input_value.endswith('>')): - node['inputs'][input_name] = input_value + if not (input_value.startswith("<") and input_value.endswith(">")): + node["inputs"][input_name] = input_value - with open(Path(copied_folder) / "flow.dag.yaml", 'w', encoding="utf-8") as f: + with open(Path(copied_folder) / "flow.dag.yaml", "w", encoding="utf-8") as f: dump_yaml(data, f) @@ -167,6 +172,8 @@ def convert_to_abs_path(file_path: str) -> str: path = Path(file_path) if path.is_absolute(): return str(path) - else: + elif path.exists(): abs = str(path.resolve()) return abs + else: + return file_path diff --git a/examples/gen_test_data/requirements.txt b/examples/gen_test_data/requirements.txt index 0cda92a0b8b..0b6cff2ad99 100644 --- a/examples/gen_test_data/requirements.txt +++ b/examples/gen_test_data/requirements.txt @@ -1,4 +1,4 @@ -promptflow +promptflow>=1.4.0 promptflow-tools llama_index configargparse diff --git a/examples/gen_test_data/requirements_cloud.txt b/examples/gen_test_data/requirements_cloud.txt index 2208d626dc1..293efd8aa03 100644 --- a/examples/gen_test_data/requirements_cloud.txt +++ b/examples/gen_test_data/requirements_cloud.txt @@ -1,4 +1,4 @@ -promptflow +promptflow>=1.4.0 promptflow-tools configargparse azure-ai-ml From 5807c8a4d091ad50e49d7355ed82d99345d7caa3 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Sun, 4 Feb 2024 15:15:54 +0800 Subject: [PATCH 054/112] Override flow component name (#1951) # Description Please add an informative description that covers that changes made by the pull request and link all relevant issues. # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. Co-authored-by: cs_lucky --- examples/gen_test_data/gen_test_data/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index d939f37b062..c9220dca3f8 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -162,7 +162,7 @@ def gen_test_data_pipeline( documents_folder=data_input, chunk_size=chunk_size ).outputs.document_node_output ) - flow_node = load_component(flow_yml_path)( + flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_flow"}])( data=data, text_chunk="${data.text_chunk}" ) From ffc3ef941965f55de966673532b8fc59ac2d8442 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:07:07 +0800 Subject: [PATCH 055/112] fix flow run on portal (#1953) ![image](https://github.com/microsoft/promptflow/assets/46446115/261c9397-8663-471f-b52f-110ababf08e8) https://ml.azure.com/prompts/flow/3e123da1-f9a5-4c91-9234-8d9ffbb39ff5/cfe95e18-49b1-46f5-bb46-8cc6969218ac/details?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/providers/Microsoft.MachineLearningServices/workspaces/promptflow-eastus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 --------- Co-authored-by: yalu4 --- .../generate_test_data_flow/flow.dag.yaml | 1 - .../generate_debug_info.py | 33 ++++--------------- .../validate_question.py | 2 +- .../validate_suggested_answer.py | 6 ++-- .../validate_text_chunk.py | 4 +-- 5 files changed, 13 insertions(+), 33 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 608f22948a8..2ecb428677e 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -96,7 +96,6 @@ nodes: type: code path: generate_debug_info.py inputs: - question_type: ${validate_question.output.question_type} text_chunk: ${inputs.text_chunk} validate_suggested_answer_output: ${validate_suggested_answer.output} text_chunk_validation_res: ${validate_text_chunk.output.validation_res} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py index fd703204772..487147153f7 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py @@ -8,59 +8,40 @@ # Please update the function name/signature per need @tool def my_python_tool( - question_type: str, text_chunk: str, text_chunk_validation_res: ValidationResult = None, validate_question_output: dict = None, validate_suggested_answer_output: dict = None, ) -> dict: - generated_question = validate_question_output["question"] question_validation_res = validate_question_output["validation_res"] generated_suggested_answer = validate_suggested_answer_output["suggested_answer"] suggested_answer_validation_res = validate_suggested_answer_output["validation_res"] is_generation_success = generated_suggested_answer != "" - is_text_chunk_valid = text_chunk_validation_res.pass_validation if text_chunk_validation_res else None - is_seed_question_valid = question_validation_res.pass_validation if question_validation_res else None + is_text_chunk_valid = text_chunk_validation_res["pass_validation"] if text_chunk_validation_res else None + is_seed_question_valid = question_validation_res["pass_validation"] if question_validation_res else None is_suggested_answer_valid = ( - suggested_answer_validation_res.pass_validation if suggested_answer_validation_res else None + suggested_answer_validation_res["pass_validation"] if suggested_answer_validation_res else None ) failed_step = "" - failed_reason = "" if not is_generation_success: if is_text_chunk_valid is False: failed_step = ValidateObj.TEXT_CHUNK - failed_reason = text_chunk_validation_res.reason elif is_seed_question_valid is False: failed_step = ValidateObj.QUESTION - failed_reason = question_validation_res.reason elif is_suggested_answer_valid is False: failed_step = ValidateObj.SUGGESTED_ANSWER - failed_reason = suggested_answer_validation_res.reason return { # TODO: support more question types like multi-context etc. # "question_type": question_type, "text_chunk": text_chunk, - "validation_summary": { - "success": is_generation_success, - "failed_step": failed_step - }, + "validation_summary": {"success": is_generation_success, "failed_step": failed_step}, "validation_details": { - ValidateObj.TEXT_CHUNK: { - "score": text_chunk_validation_res.score if text_chunk_validation_res else None, - "success": is_text_chunk_valid, - "reason": text_chunk_validation_res.reason if text_chunk_validation_res else None, - }, - ValidateObj.QUESTION: { - "success": is_seed_question_valid, - "reason": question_validation_res.reason if question_validation_res else None, - }, - ValidateObj.SUGGESTED_ANSWER: { - "success": is_suggested_answer_valid, - "reason": suggested_answer_validation_res.reason if suggested_answer_validation_res else None, - }, + ValidateObj.TEXT_CHUNK: text_chunk_validation_res, + ValidateObj.QUESTION: question_validation_res, + ValidateObj.SUGGESTED_ANSWER: suggested_answer_validation_res, }, } diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index 3442f23581a..20fcfd18c35 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -45,4 +45,4 @@ def validate_question( question = generated_question question_type = QuestionType.SIMPLE - return {"question": question, "question_type": question_type, "validation_res": validation_res} + return {"question": question, "question_type": question_type, "validation_res": validation_res._asdict()} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 491f2327618..636687957f5 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -16,7 +16,7 @@ def validate_suggested_answer( suggested_answer: str, validate_suggested_answer_prompt: str, temperature: float = 0.2, - response_format: str = "text" + response_format: str = "text", ): """ 1. Validates the given suggested answer. @@ -33,7 +33,7 @@ def validate_suggested_answer( validate_suggested_answer_prompt, suggested_answer, temperature, - response_format=response_format + response_format=response_format, ) is_valid_gt = validation_res.pass_validation failed_reason = "" @@ -42,4 +42,4 @@ def validate_suggested_answer( print(failed_reason) suggested_answer = "" - return {"suggested_answer": suggested_answer, "validation_res": validation_res} + return {"suggested_answer": suggested_answer, "validation_res": validation_res._asdict()} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py index b724a7686e4..a45b57ec3e6 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py @@ -32,6 +32,6 @@ def validate_text_chunk( ) if not text_chunk_score_res.pass_validation: print(ErrorMsg.INVALID_TEXT_CHUNK.format(context)) - return {"context": "", "validation_res": text_chunk_score_res} + return {"context": "", "validation_res": text_chunk_score_res._asdict()} - return {"context": context, "validation_res": text_chunk_score_res} + return {"context": context, "validation_res": text_chunk_score_res._asdict()} From 4326c1dffbaee46dcafbce5ee6355352af573ac8 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:03:52 +0800 Subject: [PATCH 056/112] fix batch run output json empty error (#1957) ![image](https://github.com/microsoft/promptflow/assets/46446115/9a01a146-5421-4e29-a72a-e3c598644d69) Co-authored-by: yalu4 --- examples/gen_test_data/gen_test_data/run.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index c9220dca3f8..05b7872ea66 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -54,8 +54,15 @@ def get_batch_run_output(output_path: Path): if time.time() - start_time > 300: raise Exception(f"Output jsonl file '{output_path}' is not created within 5 minutes.") - with open(output_path, "r", encoding='utf-8') as f: - output_lines = list(map(json.loads, f)) + output_lines = [] + try: + with open(output_path, "r", encoding="utf-8") as f: + output_lines = list(map(json.loads, f)) + except json.decoder.JSONDecodeError as e: + logger.warning( + f"Error reading the output file: {e}. It could be that the batch run output is empty. " + "Please check your flow and ensure it can run successfully." + ) return [ {"question": line["question"], "suggested_answer": line["suggested_answer"], "debug_info": line["debug_info"]} From 8686ef6f104a11c16ac0b83d6883253abd92be95 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:35:40 +0800 Subject: [PATCH 057/112] Filter unsupport file types (#1956) # Description ![image](https://github.com/microsoft/promptflow/assets/75061414/a517e729-a09e-4488-9f38-9f1ece5529f9) https://ml.azure.com/experiments/id/373fcd19-6749-4140-ba9e-b59be32e43db/runs/cool_truck_lm1tvjmtyk?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- docs/how-to-guides/generate-test-data.md | 1 + examples/gen_test_data/gen_test_data/common.py | 11 +++++++---- examples/gen_test_data/gen_test_data/constants.py | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index fa267c20764..8c4715d1c7a 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -11,6 +11,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - .docx - Microsoft Word - .pdf - Portable Document Format - .ipynb - Jupyter Notebook + - .txt - Text **Limitations:** diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index f7493c710e8..cb3dcbe7375 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -6,7 +6,7 @@ import typing as t from pathlib import Path -from constants import DOCUMENT_NODE, TEXT_CHUNK +from constants import DOCUMENT_NODE, TEXT_CHUNK, SUPPORT_FILE_TYPE from promptflow._utils.logger_utils import get_logger from promptflow._utils.yaml_utils import dump_yaml, load_yaml @@ -26,14 +26,17 @@ def split_document(chunk_size, documents_folder, document_node_output): logger = get_logger("doc.split") logger.info("Step 1: Start to split documents to document nodes...") # count the number of files in documents_folder, including subfolders. - num_files = sum(1 for _ in Path(documents_folder).rglob("*") if _.is_file()) + all_files = [f for f in Path(documents_folder).rglob("*") if f.is_file()] + filtered_num_files = sum(1 for _ in all_files if _.suffix.lower() in SUPPORT_FILE_TYPE) logger.info( - f"Found {num_files} files in the documents folder '{documents_folder}'. " + f"Found {len(all_files)} files in the documents folder '{documents_folder}'. " + f"Rest {filtered_num_files} files after filtering unsupported file types. " f"Using chunk size: {chunk_size} to split." ) # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. # noqa: E501 # TODO: improve on top of `SimpleDirectoryReader` with a better chunking algorithm. - chunks = SimpleDirectoryReader(documents_folder, recursive=True, encoding="utf-8").load_data() + chunks = SimpleDirectoryReader(documents_folder, required_exts=SUPPORT_FILE_TYPE, recursive=True, encoding="utf-8")\ + .load_data() # Convert documents into nodes node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) chunks = t.cast(t.List[LlamaindexDocument], chunks) diff --git a/examples/gen_test_data/gen_test_data/constants.py b/examples/gen_test_data/gen_test_data/constants.py index e6616180bd6..c2c2a2fa14f 100644 --- a/examples/gen_test_data/gen_test_data/constants.py +++ b/examples/gen_test_data/gen_test_data/constants.py @@ -1,3 +1,4 @@ DOCUMENT_NODE = "document_node" TEXT_CHUNK = "text_chunk" DETAILS_FILE_NAME ="test-data-gen-details.jsonl" +SUPPORT_FILE_TYPE = [".docx", ".pdf", ".ipynb", ".md", ".txt"] From 6bd4bcdd9c26def1d0a96751f9b06a07acefaad3 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Mon, 5 Feb 2024 12:55:40 +0800 Subject: [PATCH 058/112] rename logger name of node inputs override (#1964) rename logger name of node inputs override to make log line align with others --- examples/gen_test_data/gen_test_data/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index cb3dcbe7375..ef4e90ab926 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -139,7 +139,7 @@ def print_progress(log_file_path: str): def copy_flow_folder_and_set_node_inputs(copied_folder, flow_folder, node_inputs_override): - logger = get_logger("node_inputs_override") + logger = get_logger("data.gen") logger.info("Overriding the values of node inputs in flag.dag.yaml...") if not (Path(flow_folder) / "flow.dag.yaml").is_file(): raise ValueError(f"The file 'flag.dag.yaml' does not exist in {flow_folder}.") From 0ddcfa5a053d743e86e5ce1a2cb0507c936dcfec Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:04:10 +0800 Subject: [PATCH 059/112] [data gen] comment document_nodes_file, fix typo/broken links in doc (#1965) comment document_nodes_file, fix typo/broken links in doc --- docs/cloud/azureai/generate-test-data-cloud.md | 4 ++-- docs/how-to-guides/generate-test-data.md | 14 +++++++++----- examples/gen_test_data/config.ini.example | 9 +++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index 9cb5bcf749b..ce58e71d865 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -12,7 +12,7 @@ This guide will help you learn how to generate test data on Azure AI, so that yo - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` - .ipynb - `pip install nbconvert` - > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + > !Note: We use llama index `SimpleDirectoryReader` to load documents. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). 4. Prepare Azure AI resources in cloud. - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). @@ -30,7 +30,7 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in cloud. -- Navigate to [gen_test_data](../../../examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run --cloud diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 8c4715d1c7a..0df613abee2 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,13 +18,17 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages `pip install -r requirements.txt` +2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages. + + ```bash + pip install -r requirements.txt + ``` For specific document file types, you may need to install extra packages: - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` - .ipynb - `pip install nbconvert` - > !Note: We use llama index `SimpleDirectoryReador` in this process. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + > !Note: We use llama index `SimpleDirectoryReader` to load documents. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). 3. Install VSCode extension `Prompt flow`. @@ -50,19 +54,19 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene **Understand the prompts** - The test data generation flow contains 4 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. + The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - [*generate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - [*generate suggested answer prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - [*score text chunk prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (default 4), validation fails. - [*validate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + - [*validate suggested answer*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. ## Generate test data -- Navigate to [example_gen_test_data](../../examples/gen_test_data_gen) folder. +- Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index ea2ca5d12c5..1abd02d07c9 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -4,17 +4,18 @@ [COMMON] ; The COMMON section provides common values for all other sections. ; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. -; However, if you wish to bypass the document split process, simply provide the 'document_node_file', which is a JSONL file. -; When all these parameters are configured, the system will primarily use the 'document_node_file'. documents_folder = "" document_chunk_size = 1024 -document_nodes_file = "" +; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. +; When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. +; document_nodes_file = "" ; Test data gen flow configs flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry + ; Override some node inputs, for example, {"node_1": {"input_1": "value", "input_2": "value"}, "node_2":{"input_1": "value", "input_2": "value"}} ; Ensure the node name and the input name exist in flag.dag.yaml -; If not fill in "node_inputs_override", we will use the values in flow.dag.yaml +; If not fill in "node_inputs_override", will use the values in flow.dag.yaml node_inputs_override = {"validate_text_chunk": {"connection": "", "model_or_deployment_name": ""}, "generate_question": {"connection": "", "model_or_deployment_name": ""}, "validate_question": {"connection": "", "model_or_deployment_name": ""}, "generate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}, "validate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}} [LOCAL] From cce07d247037d8f97f52ec6d9f75724bd530be06 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Mon, 5 Feb 2024 18:38:09 +0800 Subject: [PATCH 060/112] fix stuck issue when connection name is wrong (#1975) ![image](https://github.com/microsoft/promptflow/assets/49483542/3cfbdb0b-8caf-40a2-84a4-e4c99939350a) --- examples/gen_test_data/gen_test_data/common.py | 11 ++++++++--- examples/gen_test_data/gen_test_data/run.py | 12 ++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index ef4e90ab926..4375ca9af79 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -84,7 +84,7 @@ def count_non_blank_lines(file_path): return non_blank_lines -def print_progress(log_file_path: str): +def print_progress(log_file_path: str, process): from tqdm import tqdm logger = get_logger("data.gen") @@ -103,6 +103,12 @@ def print_progress(log_file_path: str): last_data_time = time.time() with open(log_file_path, "r") as f: while True: + status = process.poll() + # status is None if not finished, 0 if finished successfully, and non-zero if failed + if status: + stdout, _ = process.communicate() + raise Exception(f"Batch run failed due to {stdout.decode('utf-8')}") + line = f.readline().strip() if line: last_data_time = time.time() # Update the time when the last data was received @@ -130,8 +136,7 @@ def print_progress(log_file_path: str): time.sleep(1) # wait for 1 second if no new line is available except Exception as e: raise Exception( - f"Error occurred while printing batch run progress {e}. " - f"See the log file '{log_file_path}' for more details." + f"Error occurred while printing batch run progress: {e}." ) finally: if pbar: diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 05b7872ea66..7b8a1da4412 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -35,13 +35,13 @@ def batch_run_flow( cmd = ( f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " - f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}'" + f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}' --debug" ) - process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.info( f"Submit batch run successfully. process id {process.pid}. Please wait for the batch run to complete..." - ) - return run_name + ) + return run_name, process def get_batch_run_output(output_path: Path): @@ -87,14 +87,14 @@ def run_local( if not should_skip_split: text_chunks_path = split_document(document_chunk_size, documents_folder, output_folder) - run_name = batch_run_flow( + run_name, process = batch_run_flow( flow_folder, text_chunks_path, flow_batch_run_size ) run_folder_path = Path.home() / f".promptflow/.runs/{run_name}" - print_progress(run_folder_path / "logs.txt") + print_progress(run_folder_path / "logs.txt", process) test_data_set = get_batch_run_output(run_folder_path / "outputs.jsonl") # Store intermedian batch run output results jsonl_str = "\n".join(map(json.dumps, test_data_set)) From 877d85b7dd6d32f2e5c0e20f59c1616743a72306 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:43:11 +0800 Subject: [PATCH 061/112] Refine generate document nodes logic (#1985) # Description 1. Add chunk_overlap to config.ini 2. Refine generate chunks logic, use docs folder as example: - Before ``` shell Split the documents and created 622 document nodes Collected 622 test data after the batch run Removed 410 invalid test data. Saved 212 valid test data ``` - After ``` shell Split the documents and created 257 document nodes Collected 257 test data after the batch run Removed 66 invalid test data. Saved 191 valid test data ``` cloud test link: https://ml.azure.com/runs/plum_boniato_9qxfctf6g7?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- examples/gen_test_data/config.ini.example | 9 ++++--- .../gen_test_data/gen_test_data/common.py | 10 +++---- .../gen_test_data/gen_test_data/components.py | 6 +++-- examples/gen_test_data/gen_test_data/run.py | 26 +++++++++++++------ 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index 1abd02d07c9..45c0bb0f950 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -3,9 +3,12 @@ [COMMON] ; The COMMON section provides common values for all other sections. -; Configure both 'document_folder' and 'document_chunk_size' if you require document splitting. +; Configure 'document_folder', 'document_chunk_size' and 'document_chunk_overlap' if you require document splitting. documents_folder = "" -document_chunk_size = 1024 +; The token chunk size for each chunk. +document_chunk_size = 512 +; The token overlap of each chunk when splitting. +document_chunk_overlap = 100 ; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. ; When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. ; document_nodes_file = "" @@ -33,7 +36,7 @@ aml_cluster = "" ; Parallel run step configs prs_instance_count = 2 -prs_mini_batch_size = 2 +prs_mini_batch_size = 1 prs_max_concurrency_per_instance = 4 prs_max_retry_count = 3 prs_run_invocation_time = 800 diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 4375ca9af79..3a28e3f74fa 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -12,7 +12,7 @@ from promptflow._utils.yaml_utils import dump_yaml, load_yaml -def split_document(chunk_size, documents_folder, document_node_output): +def split_document(chunk_size, chunk_overlap, documents_folder, document_node_output): try: from llama_index import SimpleDirectoryReader from llama_index.node_parser import SentenceSplitter @@ -34,11 +34,11 @@ def split_document(chunk_size, documents_folder, document_node_output): f"Using chunk size: {chunk_size} to split." ) # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. # noqa: E501 - # TODO: improve on top of `SimpleDirectoryReader` with a better chunking algorithm. - chunks = SimpleDirectoryReader(documents_folder, required_exts=SUPPORT_FILE_TYPE, recursive=True, encoding="utf-8")\ - .load_data() + reader = SimpleDirectoryReader(documents_folder, required_exts=SUPPORT_FILE_TYPE, recursive=True, encoding="utf-8") + SimpleDirectoryReader.supported_suffix = [] + chunks = reader.load_data() # Convert documents into nodes - node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) + node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=chunk_overlap, include_metadata=True) chunks = t.cast(t.List[LlamaindexDocument], chunks) document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=chunks) logger.info(f"Split the documents and created {len(document_nodes)} document nodes.") diff --git a/examples/gen_test_data/gen_test_data/components.py b/examples/gen_test_data/gen_test_data/components.py index ce55f51efe2..1baa3fae94f 100644 --- a/examples/gen_test_data/gen_test_data/components.py +++ b/examples/gen_test_data/gen_test_data/components.py @@ -18,7 +18,8 @@ ), ) def split_document_component( - documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") + documents_folder: Input(type="uri_folder"), chunk_size: int, chunk_overlap: int, + document_node_output: Output(type="uri_folder") ) -> str: """Split documents into document nodes. @@ -26,11 +27,12 @@ def split_document_component( documents_folder: The folder containing documents to be split. chunk_size: The size of each chunk. document_node_output: The output folder + chunk_overlap: The size of chunk overlap Returns: The folder containing the split documents. """ - return split_document(chunk_size, documents_folder, document_node_output) + return split_document(chunk_size, chunk_overlap, documents_folder, document_node_output) @command_component( diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 7b8a1da4412..b9501c50b22 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -73,6 +73,7 @@ def get_batch_run_output(output_path: Path): def run_local( documents_folder, document_chunk_size, + document_chunk_overlap, document_nodes_file, flow_folder, flow_batch_run_size, @@ -85,7 +86,7 @@ def run_local( Path(output_folder).mkdir(parents=True, exist_ok=True) if not should_skip_split: - text_chunks_path = split_document(document_chunk_size, documents_folder, output_folder) + text_chunks_path = split_document(document_chunk_size, document_chunk_overlap, documents_folder, output_folder) run_name, process = batch_run_flow( flow_folder, @@ -110,6 +111,7 @@ def run_local( def run_cloud( documents_folder, document_chunk_size, + document_chunk_overlap, document_nodes_file, flow_folder, subscription_id, @@ -153,6 +155,7 @@ def gen_test_data_pipeline( flow_yml_path: str, should_skip_doc_split: bool, chunk_size=1024, + chunk_overlap=200, instance_count=1, mini_batch_size=1, max_concurrency_per_instance=2, @@ -166,7 +169,7 @@ def gen_test_data_pipeline( data_input if should_skip_doc_split else split_document_component( - documents_folder=data_input, chunk_size=chunk_size + documents_folder=data_input, chunk_size=chunk_size, chunk_overlap=chunk_overlap ).outputs.document_node_output ) flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_flow"}])( @@ -212,6 +215,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str flow_yml_path=os.path.join(flow_folder, "flow.dag.yaml"), should_skip_doc_split=should_skip_split, chunk_size=document_chunk_size, + chunk_overlap=document_chunk_overlap, **prs_configs, ) pipeline_with_flow.compute = aml_cluster @@ -230,7 +234,10 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str parser.add_argument("--cloud", action="store_true", help="cloud flag") parser.add_argument("--documents_folder", type=str, help="Documents folder path") - parser.add_argument("--document_chunk_size", type=int, help="Document chunk size, default is 1024") + parser.add_argument("--document_chunk_size", type=int, default=512, + help="The token chunk size for each chunk, default is 512") + parser.add_argument("--document_chunk_overlap", type=int, default=100, + help="The token overlap of each chunk when splitting, default is 100") parser.add_argument( "--document_nodes_file", type=str, help="Document nodes file, default is ./document_nodes.jsonl" ) @@ -249,13 +256,14 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str parser.add_argument("--resource_group", help="AzureML workspace resource group name") parser.add_argument("--workspace_name", help="AzureML workspace name") parser.add_argument("--aml_cluster", help="AzureML cluster name") - parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") - parser.add_argument("--prs_mini_batch_size", help="Parallel run step mini batch size") + parser.add_argument("--prs_instance_count", type=int, default=2, help="Parallel run step instance count") + parser.add_argument("--prs_mini_batch_size", default=1, help="Parallel run step mini batch size") parser.add_argument( - "--prs_max_concurrency_per_instance", type=int, help="Parallel run step max concurrency per instance" + "--prs_max_concurrency_per_instance", type=int, default=4, help="Parallel run step max concurrency per instance" ) - parser.add_argument("--prs_max_retry_count", type=int, help="Parallel run step max retry count") - parser.add_argument("--prs_run_invocation_time", type=int, help="Parallel run step run invocation time") + parser.add_argument("--prs_max_retry_count", type=int, default=3, help="Parallel run step max retry count") + parser.add_argument("--prs_run_invocation_time", type=int, default=800, + help="Parallel run step run invocation time") parser.add_argument( "--prs_allowed_failed_count", type=int, help="Number of failed mini batches that could be ignored" ) @@ -295,6 +303,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str run_cloud( documents_folder, args.document_chunk_size, + args.document_chunk_overlap, document_nodes_file, copied_flow_folder, args.subscription_id, @@ -313,6 +322,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str run_local( documents_folder, args.document_chunk_size, + args.document_chunk_overlap, document_nodes_file, copied_flow_folder, args.flow_batch_run_size, From 776b712221a6c896e77bea76b85360e1ea970964 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:55:09 +0800 Subject: [PATCH 062/112] add new line (#1999) --- docs/how-to-guides/generate-test-data.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 0df613abee2..875455d4e35 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -48,6 +48,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - Fill in node inputs including `connection`, `model_or_deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to set the `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. - [*Optional*] Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). From 57266626e10c11f059db626402ef425069d7dfc1 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:27:21 +0800 Subject: [PATCH 063/112] Support data asset input (#2040) # Description In local mode, we first attempt to use the configured `document_nodes_file` if it's valid, otherwise, we fall back to `documents_folder`. In cloud mode, `document_nodes_file` is used if configured, without any validity checks because we cannot check if it is a data asset. For cloud mode, both local files and data assets can be used. **Local Tests:** 1. happy path - skip split ![image](https://github.com/microsoft/promptflow/assets/75061414/a937b8fc-4843-474f-a506-d3d1de6a1053) - has split: `documents_folder = "..\..\docs\reference\tools-reference"` ![image](https://github.com/microsoft/promptflow/assets/75061414/ca0d3a2c-14a8-424a-a927-8cbbc5a73537) 2. invalid file path and folder path ![image](https://github.com/microsoft/promptflow/assets/75061414/c0ee9255-f853-49e2-af09-fc0b61410d56) **Cloud Tests:** 1. happy path (local and asset) - local path skip split: https://ml.azure.com/runs/tough_guava_3znwhjb9sc?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 has split: https://ml.azure.com/runs/happy_flower_kr0y3yy56z?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 - data asset path skip split: https://ml.azure.com/runs/frosty_raisin_tsrhm41knv?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 has split: https://ml.azure.com/runs/neat_engine_stv9pnc0tg?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 2. invalid local file path and folder path - invalid path but not default path ![image](https://github.com/microsoft/promptflow/assets/75061414/3bb7fa53-e91d-4e0e-86d7-07503073460a) - default path ![image](https://github.com/microsoft/promptflow/assets/75061414/e14a0d7b-126a-41c6-914b-4d716da791e2) 3. invalid data asset path https://ml.azure.com/runs/lucid_brake_dvwr49x28v?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# ![image](https://github.com/microsoft/promptflow/assets/75061414/54d77749-6e3c-4cec-83a9-5e73e6bb26e1) # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- examples/gen_test_data/config.ini.example | 1 + examples/gen_test_data/gen_test_data/common.py | 8 ++++++++ examples/gen_test_data/gen_test_data/run.py | 10 ++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example index 45c0bb0f950..1a877d3112d 100644 --- a/examples/gen_test_data/config.ini.example +++ b/examples/gen_test_data/config.ini.example @@ -11,6 +11,7 @@ document_chunk_size = 512 document_chunk_overlap = 100 ; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. ; When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. +; For cloud mode, both local files and data assets can be used. ; document_nodes_file = "" ; Test data gen flow configs diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 3a28e3f74fa..f95d2c2126e 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -185,3 +185,11 @@ def convert_to_abs_path(file_path: str) -> str: return abs else: return file_path + + +def local_path_exists(path): + return Path(path).exists() + + +def non_padding_path(path): + return not (path.startswith("<") and path.endswith(">")) diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index b9501c50b22..835c99f478c 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -16,7 +16,7 @@ from common import clean_data, count_non_blank_lines, \ split_document, copy_flow_folder_and_set_node_inputs, \ - print_progress, convert_to_abs_path # noqa: E402 + print_progress, convert_to_abs_path, non_padding_path, local_path_exists # noqa: E402 from constants import TEXT_CHUNK, DETAILS_FILE_NAME # noqa: E402 logger = get_logger("data.gen") @@ -276,10 +276,11 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str documents_folder = convert_to_abs_path(args.documents_folder) flow_folder = convert_to_abs_path(args.flow_folder) output_folder = convert_to_abs_path(args.output_folder) + validate_path_func = non_padding_path if args.cloud else local_path_exists - if document_nodes_file and Path(document_nodes_file).is_file(): + if document_nodes_file and validate_path_func(document_nodes_file): should_skip_split_documents = True - elif not documents_folder or not Path(documents_folder).is_dir(): + elif not documents_folder or not validate_path_func(documents_folder): parser.error( "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" @@ -295,7 +296,8 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str "Skip step 1 'Split documents to document nodes' as received document nodes from " f"input file path '{document_nodes_file}'." ) - logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") + if Path(document_nodes_file).is_file(): + logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") copy_flow_folder_and_set_node_inputs(copied_flow_folder, args.flow_folder, args.node_inputs_override) From 356441e002114469d495b9141d0429a0f5a30ab3 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:25:05 +0800 Subject: [PATCH 064/112] Convert config.ini to config.yml (#2062) # Description **Local Tests:** 1. with split: ![image](https://github.com/microsoft/promptflow/assets/75061414/bfdc0b1c-4414-4e94-916b-e6b2f5fa6ea0) 2. no split: ![image](https://github.com/microsoft/promptflow/assets/75061414/e7ddc858-63dd-42fa-82dc-00d40030f4e6) **Cloud Tests:** 1. with split: https://ml.azure.com/runs/zen_sand_ns4ljnvv9y?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 2. no split: https://ml.azure.com/runs/mango_table_6ysb8331l0?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- .gitignore | 2 +- .../cloud/azureai/generate-test-data-cloud.md | 6 +- docs/how-to-guides/generate-test-data.md | 6 +- examples/gen_test_data/README.md | 2 +- examples/gen_test_data/config.ini.example | 44 --------- examples/gen_test_data/config.yml.example | 49 ++++++++++ examples/gen_test_data/gen_test_data/run.py | 97 ++++++------------- examples/gen_test_data/requirements.txt | 1 - examples/gen_test_data/requirements_cloud.txt | 1 - 9 files changed, 89 insertions(+), 119 deletions(-) delete mode 100644 examples/gen_test_data/config.ini.example create mode 100644 examples/gen_test_data/config.yml.example diff --git a/.gitignore b/.gitignore index f74aeafac1f..6e4297f6e7a 100644 --- a/.gitignore +++ b/.gitignore @@ -174,7 +174,7 @@ hello-world-proj/** # temp gen test data folder examples/gen_test_data/gen_test_data/*_temp # gen test data config -examples/gen_test_data/config.ini +examples/gen_test_data/config.yml # secrets **/connections.json diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index ce58e71d865..0bf66809ef5 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -21,11 +21,11 @@ This guide will help you learn how to generate test data on Azure AI, so that yo 6. Prepare config.ini - Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. - - Run command to copy [`config.ini.example`](../../../examples/gen_test_data/config.ini.example). + - Run command to copy [`config.yml.example`](../../../examples/gen_test_data/config.yml.example). ``` - cp config.ini.example config.ini + cp config.yml.example config.yml ``` - - Update the configurations in the `configs.ini`. Fill in the values in `COMMON` and `CLOUD` section following inline comment instruction. + - Update the configurations in the `configs.yml`. Fill in the values in `Common` and `Cloud` section following inline comment instruction. ## Generate test data at cloud diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 875455d4e35..b2ea66a0da7 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -36,11 +36,11 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 5. Prepare config.ini - Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. - - Run command to copy [`config.ini.example`](../../examples/gen_test_data/config.ini.example). + - Run command to copy [`config.yml.example`](../../examples/gen_test_data/config.yml.example). ``` - cp config.ini.example config.ini + cp config.yml.example config.yml ``` - - Update the configurations in the `configs.ini`. Fill in the values in `COMMON` and `LOCAL` section following inline comment instruction. + - Update the configurations in the `configs.yml`. Fill in the values in `Common` and `Local` section following inline comment instruction. ## Create a test data generation flow diff --git a/examples/gen_test_data/README.md b/examples/gen_test_data/README.md index 7bb3e6b1761..91a2870af70 100644 --- a/examples/gen_test_data/README.md +++ b/examples/gen_test_data/README.md @@ -1,3 +1,3 @@ # Generate test data -Please kindly see [this doc](..\docs\how-to-guides\generate-test-data.md) for detailed steps of how to generate test data. \ No newline at end of file +Please kindly see [this doc](../../docs/how-to-guides/generate-test-data.md) for detailed steps of how to generate test data. \ No newline at end of file diff --git a/examples/gen_test_data/config.ini.example b/examples/gen_test_data/config.ini.example deleted file mode 100644 index 1a877d3112d..00000000000 --- a/examples/gen_test_data/config.ini.example +++ /dev/null @@ -1,44 +0,0 @@ -; config.ini -; This is a sample configuration file - -[COMMON] -; The COMMON section provides common values for all other sections. -; Configure 'document_folder', 'document_chunk_size' and 'document_chunk_overlap' if you require document splitting. -documents_folder = "" -; The token chunk size for each chunk. -document_chunk_size = 512 -; The token overlap of each chunk when splitting. -document_chunk_overlap = 100 -; However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. -; When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. -; For cloud mode, both local files and data assets can be used. -; document_nodes_file = "" - -; Test data gen flow configs -flow_folder = "" ; There is must one flow.dag.yaml file under this folder as entry - -; Override some node inputs, for example, {"node_1": {"input_1": "value", "input_2": "value"}, "node_2":{"input_1": "value", "input_2": "value"}} -; Ensure the node name and the input name exist in flag.dag.yaml -; If not fill in "node_inputs_override", will use the values in flow.dag.yaml -node_inputs_override = {"validate_text_chunk": {"connection": "", "model_or_deployment_name": ""}, "generate_question": {"connection": "", "model_or_deployment_name": ""}, "validate_question": {"connection": "", "model_or_deployment_name": ""}, "generate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}, "validate_suggested_answer": {"connection": "", "model_or_deployment_name": ""}} - -[LOCAL] -; This section is for local test data generation related configuration. -output_folder = "" -flow_batch_run_size = 4 - - -[CLOUD] -; This section is for cloud test data generation related configuration. -subscription_id = "" -resource_group = "" -workspace_name = "" -aml_cluster = "" - -; Parallel run step configs -prs_instance_count = 2 -prs_mini_batch_size = 1 -prs_max_concurrency_per_instance = 4 -prs_max_retry_count = 3 -prs_run_invocation_time = 800 -prs_allowed_failed_count = -1 diff --git a/examples/gen_test_data/config.yml.example b/examples/gen_test_data/config.yml.example new file mode 100644 index 00000000000..eb6c944e499 --- /dev/null +++ b/examples/gen_test_data/config.yml.example @@ -0,0 +1,49 @@ +# Common section: this section provides common values for all other sections. Required. +# Configure 'document_folder', 'document_chunk_size' and 'document_chunk_overlap' if you require document splitting. +documents_folder: "" +document_chunk_size: 512 # The token chunk size for each chunk. +document_chunk_overlap: 100 # The token overlap of each chunk when splitting. + +# However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. +# When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. +# For cloud mode, both local files and data assets can be used. +# document_nodes_file: "" + +# Test data gen flow configs +flow_folder: "" +node_inputs_override: # Override some node inputs, if not fill in "node_inputs_override", will use the values in flow.dag.yaml + validate_text_chunk: # node name in flow.dag.yaml + connection: "" # input name of `validate_text_chunk` + model_or_deployment_name: "" + generate_question: + connection: "" + model_or_deployment_name: "" + validate_question: + connection: "" + model_or_deployment_name: "" + generate_suggested_answer: + connection: "" + model_or_deployment_name: "" + validate_suggested_answer: + connection: "" + model_or_deployment_name: "" + + +# Local section: this section is for local test data generation related configuration. Can skip if not run in local. +output_folder: "" +flow_batch_run_size: 4 + + +# Cloud section: this section is for cloud test data generation related configuration. Can skip if not run in cloud. +subscription_id: "" +resource_group: "" +workspace_name: "" +aml_cluster: "" + +# Parallel run step configs +prs_instance_count: 2 +prs_mini_batch_size: 1 +prs_max_concurrency_per_instance: 4 +prs_max_retry_count: 3 +prs_run_invocation_time: 800 +prs_allowed_failed_count: -1 \ No newline at end of file diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 835c99f478c..590ce70a4a6 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,3 +1,4 @@ +import argparse import json import os import shutil @@ -5,11 +6,10 @@ from datetime import datetime from pathlib import Path -import configargparse - from promptflow._utils.logger_utils import get_logger +from promptflow._utils.yaml_utils import load_yaml -CONFIG_FILE = (Path(__file__).parents[1] / "config.ini").resolve() +CONFIG_FILE = (Path(__file__).parents[1] / "config.yml").resolve() # in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) @@ -224,67 +224,34 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--cloud", action="store_true", help="cloud flag") + args = parser.parse_args() + if Path(CONFIG_FILE).is_file(): - parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + with open(CONFIG_FILE, 'r') as stream: + config = load_yaml(stream) else: raise Exception( f"'{CONFIG_FILE}' does not exist. " + "Please check if you are under the wrong directory or the file is missing." ) - parser.add_argument("--cloud", action="store_true", help="cloud flag") - parser.add_argument("--documents_folder", type=str, help="Documents folder path") - parser.add_argument("--document_chunk_size", type=int, default=512, - help="The token chunk size for each chunk, default is 512") - parser.add_argument("--document_chunk_overlap", type=int, default=100, - help="The token overlap of each chunk when splitting, default is 100") - parser.add_argument( - "--document_nodes_file", type=str, help="Document nodes file, default is ./document_nodes.jsonl" - ) - - parser.add_argument("--flow_folder", required=True, type=str, help="Test data generation flow folder path") - parser.add_argument( - "--flow_batch_run_size", - type=int, - help="Test data generation flow batch run size, default is 16", - ) - parser.add_argument("--node_inputs_override", type=json.loads, help="The inputs need to override") - # Configs for local - parser.add_argument("--output_folder", type=str, help="Output folder path.") - # Configs for cloud - parser.add_argument("--subscription_id", help="AzureML workspace subscription id") - parser.add_argument("--resource_group", help="AzureML workspace resource group name") - parser.add_argument("--workspace_name", help="AzureML workspace name") - parser.add_argument("--aml_cluster", help="AzureML cluster name") - parser.add_argument("--prs_instance_count", type=int, default=2, help="Parallel run step instance count") - parser.add_argument("--prs_mini_batch_size", default=1, help="Parallel run step mini batch size") - parser.add_argument( - "--prs_max_concurrency_per_instance", type=int, default=4, help="Parallel run step max concurrency per instance" - ) - parser.add_argument("--prs_max_retry_count", type=int, default=3, help="Parallel run step max retry count") - parser.add_argument("--prs_run_invocation_time", type=int, default=800, - help="Parallel run step run invocation time") - parser.add_argument( - "--prs_allowed_failed_count", type=int, help="Number of failed mini batches that could be ignored" - ) - args = parser.parse_args() - copied_flow_folder = args.flow_folder + "_" + time.strftime("%b-%d-%Y-%H-%M-%S") + "_temp" - + copied_flow_folder = config["flow_folder"] + "_" + time.strftime("%b-%d-%Y-%H-%M-%S") + "_temp" try: should_skip_split_documents = False - document_nodes_file = convert_to_abs_path(args.document_nodes_file) - documents_folder = convert_to_abs_path(args.documents_folder) - flow_folder = convert_to_abs_path(args.flow_folder) - output_folder = convert_to_abs_path(args.output_folder) + document_nodes_file = convert_to_abs_path(config.get("document_nodes_file", None)) + documents_folder = convert_to_abs_path(config.get("documents_folder", None)) + flow_folder = convert_to_abs_path(config.get("flow_folder", None)) + output_folder = convert_to_abs_path(config.get("output_folder", None)) validate_path_func = non_padding_path if args.cloud else local_path_exists if document_nodes_file and validate_path_func(document_nodes_file): should_skip_split_documents = True elif not documents_folder or not validate_path_func(documents_folder): - parser.error( + raise Exception( "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" - f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" - ) + f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'") if args.cloud: logger.info("Start to generate test data at cloud...") @@ -299,35 +266,35 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str if Path(document_nodes_file).is_file(): logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") - copy_flow_folder_and_set_node_inputs(copied_flow_folder, args.flow_folder, args.node_inputs_override) + copy_flow_folder_and_set_node_inputs(copied_flow_folder, flow_folder, config.get("node_inputs_override", None)) if args.cloud: run_cloud( documents_folder, - args.document_chunk_size, - args.document_chunk_overlap, + config.get("document_chunk_size", 512), + config.get("document_chunk_overlap", 100), document_nodes_file, copied_flow_folder, - args.subscription_id, - args.resource_group, - args.workspace_name, - args.aml_cluster, - args.prs_instance_count, - args.prs_mini_batch_size, - args.prs_max_concurrency_per_instance, - args.prs_max_retry_count, - args.prs_run_invocation_time, - args.prs_allowed_failed_count, + config["subscription_id"], + config["resource_group"], + config["workspace_name"], + config["aml_cluster"], + config.get("prs_instance_count", 2), + config.get("prs_mini_batch_size", 1), + config.get("prs_max_concurrency_per_instance", 4), + config.get("prs_max_retry_count", 3), + config.get("prs_run_invocation_time", 800), + config.get("prs_allowed_failed_count", -1), should_skip_split_documents, ) else: run_local( documents_folder, - args.document_chunk_size, - args.document_chunk_overlap, + config.get("document_chunk_size", 512), + config.get("document_chunk_overlap", 100), document_nodes_file, copied_flow_folder, - args.flow_batch_run_size, + config.get("flow_batch_run_size", 16), output_folder, should_skip_split_documents, ) diff --git a/examples/gen_test_data/requirements.txt b/examples/gen_test_data/requirements.txt index 0b6cff2ad99..3e1dedd5778 100644 --- a/examples/gen_test_data/requirements.txt +++ b/examples/gen_test_data/requirements.txt @@ -1,4 +1,3 @@ promptflow>=1.4.0 promptflow-tools llama_index -configargparse diff --git a/examples/gen_test_data/requirements_cloud.txt b/examples/gen_test_data/requirements_cloud.txt index 293efd8aa03..e055a61e61a 100644 --- a/examples/gen_test_data/requirements_cloud.txt +++ b/examples/gen_test_data/requirements_cloud.txt @@ -1,5 +1,4 @@ promptflow>=1.4.0 promptflow-tools -configargparse azure-ai-ml mldesigner From c0bb62c36fcba1534f24f5fb7a9ac51fec6dba08 Mon Sep 17 00:00:00 2001 From: chenslucky <75061414+chenslucky@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:53:29 +0800 Subject: [PATCH 065/112] Tune prompt to avoid question with `in this context/in given code/in table` (#2107) # Description For some text chunks, compare the questions before and after modification. Use the model "gpt-4-1106-preview". Each text chunk run 5 to 10 times continuously to verify the results. ### QA 1 **before question:** `What is the purpose of the condition_output in the given pipeline code?` **before answer:** `The purpose of the condition_output in the given pipeline code is to selectively return one of two inputs based on a condition that is evaluated at runtime. If the condition evaluates to True, condition_output will return the first input (input_a), otherwise, it will return the second input (input_b). This allows for dynamic control of the data flow within the pipeline, depending on the results of previous tasks or workflow inputs.` **after question:** `How does the condition_output function decide which input to return?` **after answer:** `The condition_output function decides which input to return based on the result of a boolean condition. If the condition evaluates to True, it returns input_a; if the condition evaluates to False, it returns input_b.` ### QA 2 **before question:** `What are macros used for in the context of scheduling services?` **before answer:** `Macros are used in scheduling services to manipulate timestamps in various ways, such as adding days, hours, minutes, or seconds to a timestamp, converting time zones, extracting specific parts of a date like the day of the year, month, or week, finding the start of a month, day, or hour, formatting a timestamp into a string, and adding or subtracting time units from a timestamp. These operations help in dynamically setting the times when scheduled tasks should run or in processing time-related data within the tasks.` **after question:** `What are the supported macros for manipulating timestamps in a schedule service?` **after answer:** `The supported macros for manipulating timestamps in a schedule service are:\n\n- `trigger_time`: Time when schedule service triggered the pipeline.\n- `add_days`: Add a number of days to a timestamp.\n- `add_hours`: Add a number of hours to a timestamp.\n- `add_minutes`: Add a number of minutes to a timestamp.\n- `add_seconds`: Add a number of seconds to a timestamp.\n- `convert_time_zone`: Convert a timestamp from the source time zone to the target time zone.\n- `day_of_year`: Return the day of the year from a timestamp.\n- `day_of_month`: Return the day of the month from a timestamp.\n- `day_of_week`: Return the day of the week from a timestamp.\n- `start_of_month`: Return the start of the month for a timestamp.\n- `start_of_day`: Return the start of the day for a timestamp.\n- `start_of_hour`: Return the start of the hour for a timestamp.\n- `format_date_time`: Return the timestamp as a string in optional format.\n- `add_to_time`: Add a number of time units to a timestamp.\n- `substract_from_time`: Subtract a number of time units from a timestamp.` ### QA 3 **before question:** `What does \"JOB_HEARTBEAT_TIMEOUT_SECONDS\" indicate in the context of job monitoring?` **before answer:** `\"JOB_HEARTBEAT_TIMEOUT_SECONDS\" represents the amount of time you are willing to allow a job to run without any indication of progress before considering the resources used as wasted due to a potential hang. It is not meant to be a strict limit on the expected duration of an epoch but rather a threshold to detect and alert on job hangs without causing false positives.` **after question:** `How should the JOB_HEARTBEAT_TIMEOUT_SECONDS be set in relation to epoch duration to avoid false alerts?` **after answer:** `JOB_HEARTBEAT_TIMEOUT_SECONDS should be set longer than the expected duration of an epoch to prevent false positive alerts. It should be a measure of the amount of compute resources you are willing to lose while a hang goes undetected, rather than a tight limit on your epoch's expected time.` ### QA 4 **before question:** `What types are supported for parallel-for output in the given mapping table?` **before answer:** `The supported parallel-for output types are:\n\n- mltable\n- string` **after question:** `What types are supported for parallel-for output in Azure ML pipelines?` **after answer:** `The supported types for parallel-for output in Azure ML pipelines are mltable and string.` ### Test using docs: no 'in this context/in given code/in table' pattern anymore ![image](https://github.com/microsoft/promptflow/assets/75061414/098aa161-fa91-4555-a7d3-319dbf97ced3) # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: cs_lucky --- .../generate_question_prompt.jinja2 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 index dcc23077e41..cc11b965f21 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 @@ -5,9 +5,10 @@ Your task is to formulate a question from given context satisfying the rules giv 1.The question should better be framed from the overall context, serving as a general question, rather than just framed from some details. 2.The question should be specific and answerable from the given context. 3.The question must be reasonable and must be understood and responded by humans. -4.The question should not contains phrases like 'provided context' in the question. -5.The question should not contain any links. -6.The question should not contain more than 20 words, use abbreviation wherever possible. +4.The question should not contain phrases like 'provided' or 'given' in the question. +5.The question should be a question asked by the hypothetical user without any given context. +6.The question should not contain any links. +7.The question should not contain more than 20 words, use abbreviation wherever possible. # user: context: From f6dca7c0ea9c3b8e30b61fa3a8e8ae94a5b98cc9 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:56:02 +0800 Subject: [PATCH 066/112] Add summary info of data gen details (#2161) **Local experience** Extra file with name `test-data-gen-summary.json`, ![image](https://github.com/microsoft/promptflow/assets/46446115/dda55db7-282f-454d-b965-7eb013a1775c) File content: ![image](https://github.com/microsoft/promptflow/assets/46446115/0f1b1080-40ac-434b-afc5-f2f5c3530ad4) **Cloud experience** Extra node `summarize generation details` to analyze gen details: - With document split https://ml.azure.com/runs/sincere_cheese_6qmhnvcwgy?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# ![image](https://github.com/microsoft/promptflow/assets/46446115/2ff4b590-4f40-4bc1-b1d1-87313dfab613) - Without document split https://ml.azure.com/runs/placid_tongue_zrwsn248pf?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# ![image](https://github.com/microsoft/promptflow/assets/46446115/a0603d45-384c-4f1a-aaeb-a36749c84693) --------- Co-authored-by: yalu4 --- .../gen_test_data/gen_test_data/common.py | 91 +++++++++++-- .../gen_test_data/gen_test_data/components.py | 42 +++++- .../gen_test_data/gen_test_data/constants.py | 6 +- examples/gen_test_data/gen_test_data/run.py | 122 ++++++++++-------- 4 files changed, 189 insertions(+), 72 deletions(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index f95d2c2126e..8475b3a99a6 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -6,7 +6,7 @@ import typing as t from pathlib import Path -from constants import DOCUMENT_NODE, TEXT_CHUNK, SUPPORT_FILE_TYPE +from constants import DOCUMENT_NODE, NODES_FILE_NAME, SUPPORT_FILE_TYPE, TEXT_CHUNK from promptflow._utils.logger_utils import get_logger from promptflow._utils.yaml_utils import dump_yaml, load_yaml @@ -38,17 +38,19 @@ def split_document(chunk_size, chunk_overlap, documents_folder, document_node_ou SimpleDirectoryReader.supported_suffix = [] chunks = reader.load_data() # Convert documents into nodes - node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=chunk_overlap, include_metadata=True) + node_parser = SentenceSplitter.from_defaults( + chunk_size=chunk_size, chunk_overlap=chunk_overlap, include_metadata=True + ) chunks = t.cast(t.List[LlamaindexDocument], chunks) document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=chunks) logger.info(f"Split the documents and created {len(document_nodes)} document nodes.") - document_nodes_output_path = document_node_output / Path("document_nodes.jsonl") + document_nodes_output_path = document_node_output / Path(NODES_FILE_NAME) with open(document_nodes_output_path, "wt") as text_file: for doc in document_nodes: print(json.dumps({TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()}), file=text_file) logger.info(f"Saved document nodes to '{document_nodes_output_path}'.") - return str((Path(document_node_output) / "document_nodes.jsonl")) + return str(Path(document_node_output) / NODES_FILE_NAME) def clean_data(test_data_set: list, test_data_output_path: str): @@ -98,7 +100,7 @@ def print_progress(log_file_path: str, process): if time.time() - start_time > 300: raise Exception(f"Log file '{log_file_path}' is not created within 5 minutes.") - pbar = None + progress_bar = None try: last_data_time = time.time() with open(log_file_path, "r") as f: @@ -117,12 +119,12 @@ def print_progress(log_file_path: str, process): continue finished, total = map(int, match.groups()) - if pbar is None: - pbar = tqdm(total=total, desc="Processing", file=sys.stdout) - pbar.update(finished - pbar.n) + if progress_bar is None: + progress_bar = tqdm(total=total, desc="Processing", file=sys.stdout) + progress_bar.update(finished - progress_bar.n) if finished == total: - pbar.close() + progress_bar.close() logger.info("Batch run is completed.") break @@ -135,12 +137,10 @@ def print_progress(log_file_path: str, process): else: time.sleep(1) # wait for 1 second if no new line is available except Exception as e: - raise Exception( - f"Error occurred while printing batch run progress: {e}." - ) + raise Exception(f"Error occurred while printing batch run progress: {e}.") finally: - if pbar: - pbar.close() + if progress_bar: + progress_bar.close() def copy_flow_folder_and_set_node_inputs(copied_folder, flow_folder, node_inputs_override): @@ -193,3 +193,66 @@ def local_path_exists(path): def non_padding_path(path): return not (path.startswith("<") and path.endswith(">")) + + +def _retrieve_file_names_from_document_nodes_file(document_nodes_file_path) -> t.List[str]: + text_info = {} + with open(document_nodes_file_path, "r") as file: + for line in file: + line_json = json.loads(line) + text_chunk = line_json[TEXT_CHUNK] + document_node = json.loads(line_json["document_node"]) + file_path = document_node["metadata"]["file_path"] + text_info[text_chunk] = file_path + return text_info + + +def _count_lines(file_path) -> int: + with open(file_path, "r") as f: + return sum(1 for _ in f) + + +def summarize_batch_run_res(gen_details_file_path, document_nodes_file_path, output_file_path): + success_count = 0 + validate_failed_count = 0 + validate_failed_steps = {} + validate_failed_distribution = {} + + nodes_file_lines_count = _count_lines(document_nodes_file_path) + document_nodes_info = _retrieve_file_names_from_document_nodes_file(document_nodes_file_path) + + with open(gen_details_file_path, "r") as details_f: + for details_line in details_f: + data = json.loads(details_line) + if data["debug_info"] == "(Failed)": + continue + + if data["debug_info"]["validation_summary"]["success"]: + success_count += 1 + else: + validate_failed_count += 1 + failed_step = data["debug_info"]["validation_summary"]["failed_step"] + + if failed_step in validate_failed_steps: + validate_failed_steps[failed_step] += 1 + else: + validate_failed_steps[failed_step] = 1 + validate_failed_distribution[failed_step] = {} + + document_name = document_nodes_info[data["debug_info"]["text_chunk"]] + if document_name in validate_failed_distribution[failed_step]: + validate_failed_distribution[failed_step][document_name] += 1 + else: + validate_failed_distribution[failed_step][document_name] = 1 + + data = { + "total_count": nodes_file_lines_count, + "success_count": success_count, + "run_failed_count": nodes_file_lines_count - success_count - validate_failed_count, + "validate_failed_count": validate_failed_count, + "validate_failed_steps": validate_failed_steps, + "validate_failed_distribution": validate_failed_distribution, + } + + with open(output_file_path, "w") as file: + json.dump(data, file, indent=4) diff --git a/examples/gen_test_data/gen_test_data/components.py b/examples/gen_test_data/gen_test_data/components.py index 1baa3fae94f..583ec610dbe 100644 --- a/examples/gen_test_data/gen_test_data/components.py +++ b/examples/gen_test_data/gen_test_data/components.py @@ -1,7 +1,8 @@ import json from pathlib import Path -from common import clean_data, split_document +from common import clean_data, split_document, summarize_batch_run_res +from constants import NODES_FILE_NAME, PARALLEL_RUN_STEP_FILE_NAME, SUMMARY_FILE_NAME, TEST_DATA_FILE_NAME from mldesigner import Input, Output, command_component conda_file = Path(__file__).parent.parent / "conda.yml" @@ -18,8 +19,10 @@ ), ) def split_document_component( - documents_folder: Input(type="uri_folder"), chunk_size: int, chunk_overlap: int, - document_node_output: Output(type="uri_folder") + documents_folder: Input(type="uri_folder"), + chunk_size: int, + chunk_overlap: int, + document_node_output: Output(type="uri_folder"), ) -> str: """Split documents into document nodes. @@ -47,12 +50,41 @@ def split_document_component( def clean_data_component( test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") ) -> str: - test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" + test_data_set_path = Path(test_data_set_folder) / PARALLEL_RUN_STEP_FILE_NAME with open(test_data_set_path, "r") as f: data = [json.loads(line) for line in f] - test_data_output_path = test_data_output / Path("test_data_set.jsonl") + test_data_output_path = test_data_output / Path(TEST_DATA_FILE_NAME) clean_data(data, test_data_output_path) return str(test_data_output_path) + + +@command_component( + name="summarize_generation_details_component", + display_name="summarize generation details", + description="Summarize generation details.", + environment=dict( + conda_file=conda_file, + image=env_image, + ), +) +def summarize_generation_details_component( + document_node_output: Input(type="uri_folder"), + test_data_set_folder: Input(type="uri_folder"), + summary_output: Output(type="uri_folder"), +) -> str: + test_data_set_path = Path(test_data_set_folder) / PARALLEL_RUN_STEP_FILE_NAME + document_node_output_path = Path(document_node_output) + + summary_output_path = summary_output / Path(SUMMARY_FILE_NAME) + if document_node_output_path.is_dir(): + document_node_output_path = document_node_output_path / NODES_FILE_NAME + summarize_batch_run_res( + gen_details_file_path=test_data_set_path, + document_nodes_file_path=document_node_output_path, + output_file_path=summary_output_path, + ) + + return str(summary_output_path) diff --git a/examples/gen_test_data/gen_test_data/constants.py b/examples/gen_test_data/gen_test_data/constants.py index c2c2a2fa14f..b6ffa88298f 100644 --- a/examples/gen_test_data/gen_test_data/constants.py +++ b/examples/gen_test_data/gen_test_data/constants.py @@ -1,4 +1,8 @@ DOCUMENT_NODE = "document_node" TEXT_CHUNK = "text_chunk" -DETAILS_FILE_NAME ="test-data-gen-details.jsonl" +NODES_FILE_NAME = "document_nodes.jsonl" +DETAILS_FILE_NAME = "test-data-gen-details.jsonl" +PARALLEL_RUN_STEP_FILE_NAME = "parallel_run_step.jsonl" +SUMMARY_FILE_NAME = "test-data-gen-summary.json" +TEST_DATA_FILE_NAME = "test-data.jsonl" SUPPORT_FILE_TYPE = [".docx", ".pdf", ".ipynb", ".md", ".txt"] diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 590ce70a4a6..7a728646ce9 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -14,10 +14,18 @@ # in order to import from absolute path, which is required by mldesigner os.sys.path.insert(0, os.path.abspath(Path(__file__).parent)) -from common import clean_data, count_non_blank_lines, \ - split_document, copy_flow_folder_and_set_node_inputs, \ - print_progress, convert_to_abs_path, non_padding_path, local_path_exists # noqa: E402 -from constants import TEXT_CHUNK, DETAILS_FILE_NAME # noqa: E402 +from common import ( # noqa: E402 + clean_data, + convert_to_abs_path, + copy_flow_folder_and_set_node_inputs, + count_non_blank_lines, + local_path_exists, + non_padding_path, + print_progress, + split_document, + summarize_batch_run_res, +) +from constants import DETAILS_FILE_NAME, SUMMARY_FILE_NAME, TEST_DATA_FILE_NAME, TEXT_CHUNK # noqa: E402 logger = get_logger("data.gen") @@ -40,7 +48,7 @@ def batch_run_flow( process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.info( f"Submit batch run successfully. process id {process.pid}. Please wait for the batch run to complete..." - ) + ) return run_name, process @@ -71,14 +79,14 @@ def get_batch_run_output(output_path: Path): def run_local( - documents_folder, - document_chunk_size, - document_chunk_overlap, - document_nodes_file, - flow_folder, - flow_batch_run_size, - output_folder, - should_skip_split, + documents_folder: str, + document_chunk_size: int, + document_chunk_overlap: int, + document_nodes_file: str, + flow_folder: str, + flow_batch_run_size: int, + output_folder: str, + should_skip_split: bool, ): text_chunks_path = document_nodes_file output_folder = Path(output_folder) / datetime.now().strftime("%b-%d-%Y-%H-%M-%S") @@ -88,11 +96,7 @@ def run_local( if not should_skip_split: text_chunks_path = split_document(document_chunk_size, document_chunk_overlap, documents_folder, output_folder) - run_name, process = batch_run_flow( - flow_folder, - text_chunks_path, - flow_batch_run_size - ) + run_name, process = batch_run_flow(flow_folder, text_chunks_path, flow_batch_run_size) run_folder_path = Path.home() / f".promptflow/.runs/{run_name}" print_progress(run_folder_path / "logs.txt", process) @@ -103,28 +107,39 @@ def run_local( with open(batch_run_details_file, "wt") as text_file: print(f"{jsonl_str}", file=text_file) - clean_data_output = Path(output_folder) / "test-data.jsonl" + clean_data_output = Path(output_folder) / TEST_DATA_FILE_NAME clean_data(test_data_set, clean_data_output) logger.info(f"More debug info of test data generation can be found in '{batch_run_details_file}'.") + try: + summary_output_file = Path(output_folder) / SUMMARY_FILE_NAME + summarize_batch_run_res( + gen_details_file_path=batch_run_details_file, + document_nodes_file_path=text_chunks_path, + output_file_path=summary_output_file, + ) + logger.info(f"Check test data generation summary in '{summary_output_file}'.") + except Exception as e: + logger.warning(f"Error to analyze batch run results: {e}") + def run_cloud( - documents_folder, - document_chunk_size, - document_chunk_overlap, - document_nodes_file, - flow_folder, - subscription_id, - resource_group, - workspace_name, - aml_cluster, - prs_instance_count, - prs_mini_batch_size, - prs_max_concurrency_per_instance, - prs_max_retry_count, - prs_run_invocation_time, - prs_allowed_failed_count, - should_skip_split, + documents_folder: str, + document_chunk_size: int, + document_chunk_overlap: int, + document_nodes_file: str, + flow_folder: str, + subscription_id: str, + resource_group: str, + workspace_name: str, + aml_cluster: str, + prs_instance_count: int, + prs_mini_batch_size: int, + prs_max_concurrency_per_instance: int, + prs_max_retry_count: int, + prs_run_invocation_time: int, + prs_allowed_failed_count: int, + should_skip_split: bool, ): # lazy import azure dependencies try: @@ -151,19 +166,19 @@ def run_cloud( ] ) def gen_test_data_pipeline( - data_input: V2Input, - flow_yml_path: str, - should_skip_doc_split: bool, - chunk_size=1024, - chunk_overlap=200, - instance_count=1, - mini_batch_size=1, - max_concurrency_per_instance=2, - max_retry_count=3, - run_invocation_time=600, - allowed_failed_count=-1, + data_input: V2Input, + flow_yml_path: str, + should_skip_doc_split: bool, + chunk_size=1024, + chunk_overlap=200, + instance_count=1, + mini_batch_size=1, + max_concurrency_per_instance=2, + max_retry_count=3, + run_invocation_time=600, + allowed_failed_count=-1, ): - from components import clean_data_component, split_document_component + from components import clean_data_component, split_document_component, summarize_generation_details_component data = ( data_input @@ -173,8 +188,7 @@ def gen_test_data_pipeline( ).outputs.document_node_output ) flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_flow"}])( - data=data, - text_chunk="${data.text_chunk}" + data=data, text_chunk="${data.text_chunk}" ) flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance @@ -184,6 +198,9 @@ def gen_test_data_pipeline( # Should use `mount` mode to ensure PRS complete merge output lines. flow_node.outputs.flow_outputs.mode = "mount" clean_data_component(test_data_set_folder=flow_node.outputs.flow_outputs).outputs.test_data_output + summarize_generation_details_component( + document_node_output=data, test_data_set_folder=flow_node.outputs.flow_outputs + ).outputs.summary_output def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) @@ -225,11 +242,11 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("--cloud", action="store_true", help="cloud flag") + parser.add_argument("--cloud", action="store_true", help="Run test data generation at cloud.") args = parser.parse_args() if Path(CONFIG_FILE).is_file(): - with open(CONFIG_FILE, 'r') as stream: + with open(CONFIG_FILE, "r") as stream: config = load_yaml(stream) else: raise Exception( @@ -251,7 +268,8 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str elif not documents_folder or not validate_path_func(documents_folder): raise Exception( "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" - f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'") + f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" + ) if args.cloud: logger.info("Start to generate test data at cloud...") From 88c546df1e6217f458296866356752527bbc7264 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Fri, 15 Mar 2024 15:02:26 +0800 Subject: [PATCH 067/112] add eval flows and simulation flow --- .../eval-flow-for-multi-turn/README.md | 47 +++ .../aggregate_results.py | 25 ++ .../answer_relevancy.jinja2 | 28 ++ .../eval-flow-for-multi-turn/concat_scores.py | 34 ++ .../conversation_quality_prompt.jinja2 | 40 ++ .../covert_chat_history_to_conversation.py | 9 + .../creativity.jinja2 | 31 ++ .../eval-flow-for-multi-turn/flow.dag.yaml | 202 +++++++++++ .../eval-flow-for-multi-turn/grounding.py | 43 +++ .../grounding_prompt.jinja2 | 29 ++ .../eval-flow-for-multi-turn/requirements.txt | 2 + .../select_metrics.py | 17 + .../validate_input.py | 28 ++ .../eval-flow-for-single-turn/README.md | 64 ++++ .../eval-flow-for-single-turn/aggregate.py | 25 ++ .../answer_correctness.jinja2 | 28 ++ .../answer_quality.jinja2 | 39 ++ .../answer_relevancy.jinja2 | 45 +++ .../answer_similarity.jinja2 | 22 ++ .../calculate_answer_correctness.py | 39 ++ .../calculate_answer_relevancy.py | 27 ++ .../calculate_context_recall.py | 29 ++ .../concat_scores.py | 42 +++ .../context_precision.jinja2 | 32 ++ .../context_recall.jinja2 | 76 ++++ .../creativity.jinja2 | 30 ++ .../eval-flow-for-single-turn/flow.dag.yaml | 343 ++++++++++++++++++ .../eval-flow-for-single-turn/flow.meta.yaml | 11 + .../grounding.jinja2 | 29 ++ .../handle_generated_question.py | 12 + .../requirements.txt | 2 + .../eval-flow-for-single-turn/samples.json | 8 + .../select_metrics.py | 14 + .../validate_input.py | 32 ++ .../standard/simulation-flow/If_continue.py | 9 + .../flows/standard/simulation-flow/README.md | 36 ++ .../standard/simulation-flow/call_llm_chat.py | 56 +++ .../standard/simulation-flow/flow.dag.yaml | 78 ++++ .../standard/simulation-flow/flow_output.py | 9 + .../simulation-flow/human_prompt.jinja2 | 27 ++ .../standard/simulation-flow/requirements.txt | 0 .../verify_if_conversation_stopped.jinja2 | 32 ++ 42 files changed, 1731 insertions(+) create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/README.md create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py create mode 100644 examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/README.md create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/samples.json create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py create mode 100644 examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py create mode 100644 examples/flows/standard/simulation-flow/If_continue.py create mode 100644 examples/flows/standard/simulation-flow/README.md create mode 100644 examples/flows/standard/simulation-flow/call_llm_chat.py create mode 100644 examples/flows/standard/simulation-flow/flow.dag.yaml create mode 100644 examples/flows/standard/simulation-flow/flow_output.py create mode 100644 examples/flows/standard/simulation-flow/human_prompt.jinja2 create mode 100644 examples/flows/standard/simulation-flow/requirements.txt create mode 100644 examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/README.md b/examples/flows/evaluation/eval-flow-for-multi-turn/README.md new file mode 100644 index 00000000000..5900b26e53e --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/README.md @@ -0,0 +1,47 @@ +# Evaluation flow for single turn: + +This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. + +## What you will learn + +This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: + +* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. + +grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* answer_relevancy: Measure whether the answer is relevancy to the question based on provided question, context and answer. + +answer_relevancy is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* answer_quality: Measures the answer quality for each of the following factors based on provided question and answer: + - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? + - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? + - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? + - Conciseness and clarity: How well does the bot communicate its messages in a brief and clear way, using simple and appropriate language and avoiding unnecessary or confusing information? How easy is it for the user to understand and follow the bot responses, and how well do they match the user's needs and expectations? + - Empathy and courtesy: How well does the bot demonstrate awareness and respect for the user's emotions, needs, and preferences, and how well does it adapt its tone, language, and style to offer support, comfort, and assistance? Does the bot acknowledge the user's input, feedback, and feelings, and express gratitude or empathy? Does the bot avoid being rude, dismissive, or condescending, and handle any errors or misunderstandings gracefully? + - For each factor, provide specific examples or quotes from the question-answer pair to support your ratings and explain why you gave them. + - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") + - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". + +answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* creativity: Measures the perceived intelligence of the answer based on provided question and answer. +Perceived intelligence definition: +Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. +Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. +Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. +A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. +A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. + +creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + + +## Prerequisites + +- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, answer_relevancy. + +## Tools used in this flow +- LLM tool +- Python tool +- Embedding tool \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py b/examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py new file mode 100644 index 00000000000..250169fab23 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py @@ -0,0 +1,25 @@ +from typing import List +from promptflow import tool, log_metric +import numpy as np + + +@tool +def aggregate_variants_results(results: List[dict], metrics: str): + aggregate_results = {} + for result in results: + for name, value in result.items(): + if name in metrics[0]: + if name not in aggregate_results.keys(): + aggregate_results[name] = [] + try: + float_val = float(value) + except Exception: + float_val = np.nan + aggregate_results[name].append(float_val) + + for name, value in aggregate_results.items(): + if name in metrics[0]: + aggregate_results[name] = np.nanmean(value) + aggregate_results[name] = round(aggregate_results[name], 2) + log_metric(name, aggregate_results[name]) + return aggregate_results diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 new file mode 100644 index 00000000000..b489ea9c704 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 @@ -0,0 +1,28 @@ +system: +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the relevancy of bot responses in a conversation to user questions. Your job is to compute an accurate evaluation score using the provided evaluation metric. + +Relevance measures how well the bot responses addresses the main aspects of the user questions. Consider whether all and only the important aspects are contained in the bot responses when evaluating relevance, score the relevance of the bot responses on a scale of 1 (completely lacks relevance) to 5 (perfect relevance) + +- If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the relevancy quality of the conversation and the rating a score for it, and provide some suggestions for how the bot could handle it better. + +Tips: +- You should read user's question more carefully and try to understand what they are looking for and why. +- You should compare the bot's response to the user's question and see if it matches the criteria of relevance. +- You should score and provide feedback for the whole conversation as a whole, not for each bot response individually. However, you can mention if some responses are better or worse than others, and why. +- You should try to be objective and constructive in your evaluation, and use evidence and examples from the transcript to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. +- The output should be in json format to include score and overall keys. + +Example: +Example Conversation: +{ + "conversation": "User: Why is the sky blue?\nBot: The sky is blue because of the way the atmosphere scatters light.\nUser: How does it scatter light?\nBot: The atmosphere is made up of tiny particles, such as water vapor and dust. When light hits these particles, it is scattered in all directions.\nUser: Why does the sky turn red at sunset?\nBot: During the day, the sky is blue because blue light is scattered more than other colors. At sunset, the light travels a longer distance through the atmosphere, so more of the blue light is scattered out, leaving the red and yellow light." +} +Example Output: +{ + "score": 5 + "overall": "The bot's responses are highly relevant to the user's questions.The user asked about why the sky is blue, how light is scattered, and why the sky turns red at sunset. The bot provided clear, concise, and accurate answers to all these questions.Therefore, I would rate the relevance of the bot's responses as 5 out of 5. \n\nThe bot did an excellent job in this conversation. However, to further improve, the bot could provide even more detailed explanations or use simpler language if it detects that the user is a child or someone with no background in the topic." +} + +Conversation: +{{conversation}} +Output: diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py new file mode 100644 index 00000000000..e1b34135a1b --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py @@ -0,0 +1,34 @@ +from promptflow import tool +import numpy as np +import re +import json + +def get_score(result): + try: + if result is not None: + # Parse the JSON string + result_dict = json.loads(result) + + # Extract the score value + score = result_dict.get('score', None) + print("result: ") + print(score) + return score + else: + return None + except json.JSONDecodeError: + print("Invalid JSON string.") + return None + +@tool +def concat_results(answer_relevancy: str = None, + answer_quality: str = None, + creativity: str = None, + grounding: str = None): + + results = {'answer_relevancy': get_score(answer_relevancy), + 'answer_quality': get_score(answer_quality), + 'creativity': get_score(creativity), + 'grounding': grounding} + + return results diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 new file mode 100644 index 00000000000..c4aba2ba8c0 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 @@ -0,0 +1,40 @@ +system: +- You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. You need to read the transcript carefully and identify the main topic, question, or issue of the conversation, as well as the purpose and expectations of the interaction. +- You need to rate all the bot responses together on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. + - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its responses, and cite its sources or evidence if applicable? + - Coherence and completeness: How well does the bot maintain a logical and consistent flow of conversation that follows the user's input and the purpose of the dialogue, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? + - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? How appropriate and consistent is the bot's tone for the context, purpose, and audience of the conversation, and how well does it match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? + - Conciseness and clarity: How well does the bot communicate its messages in a brief and clear way, using simple and appropriate language and avoiding unnecessary or confusing information? How easy is it for the user to understand and follow the bot responses, and how well do they match the user's needs and expectations? + - Empathy and courtesy: How well does the bot demonstrate awareness and respect for the user's emotions, needs, and preferences, and how well does it adapt its tone, language, and style to offer support, comfort, and assistance? Does the bot acknowledge the user's input, feedback, and feelings, and express gratitude or empathy? Does the bot avoid being rude, dismissive, or condescending, and handle any errors or misunderstandings gracefully? + - For each factor, provide specific examples or quotes from the transcript to support your ratings and explain why you gave them. +- Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") +- Give an overall impression of the quality and effectiveness of the responses and suggest any areas for improvement or commendation. Write it in "Overall". + +- If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the quality of the conversation and the ratings for each factor, and provide some suggestions for how the bot could handle these situations better. + +Tips: +- You can write your feedback as bullet points, sentences, or paragraphs, but make sure they are organized and easy to read. +- You should rate and provide feedback for the whole conversation as a whole, not for each bot response individually. However, you can mention if some responses are better or worse than others, and why. +- You should try to be objective and constructive in your evaluation, and use evidence and examples from the transcript to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. +- The output should be in json format. + + +Example: +Example Conversation: +{ + "conversation": "User: Why is the sky blue?\nBot: The sky is blue because of the way the atmosphere scatters light.\nUser: How does it scatter light?\nBot: The atmosphere is made up of tiny particles, such as water vapor and dust. When light hits these particles, it is scattered in all directions.\nUser: Why does the sky turn red at sunset?\nBot: During the day, the sky is blue because blue light is scattered more than other colors. At sunset, the light travels a longer distance through the atmosphere, so more of the blue light is scattered out, leaving the red and yellow light." +} +Example Output: +{ + "accuracy and relevance": 5, + "coherence and completeness": 4, + "engagement and tone": 3.5, + "conciseness and clarity": 3, + "empathy and courtesy": 3, + "score": 3.925 + "overall": "The bot responses are clear and concise, but they do not provide any relevant or helpful information to answer the user's question about the sky. The bot could have explained the science behind why the sky is blue and why it turns red at sunset, and provided some references or sources to support its claims. The bot could also have asked the user to clarify their question, or asked some follow-up questions to better understand the user's intent and expectations." +} + +Conversation: +{{conversation}} +Output: diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py b/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py new file mode 100644 index 00000000000..09994ca08ec --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py @@ -0,0 +1,9 @@ +from promptflow import tool + +@tool +def covert_chat_history_to_conversation(chat_history: list) -> dict: + conversation = "" + for i in chat_history: + conversation += f"User: {i['inputs']['question']}\nBot: {i['outputs']['answer']}\n" + conversation_format = {"conversation": conversation} + return conversation_format diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 new file mode 100644 index 00000000000..6fed8a30e82 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 @@ -0,0 +1,31 @@ +System: +You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. Your job is to assess the perceived intelligence of all the bot response in the coversation. +Perceived intelligence definition: +Perceived intelligence is the degree to which a bot can impress the user with its responses, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the conversation more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its responses according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. +Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's responses, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. +Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. +A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the conversation more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. +A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant responses that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. + +Tips: +- You should read the user's question more carefully and try to understand what they are looking for and why. +- You should also compare the bot's response to the user's question and see if it matches the criteria of perceived intelligence, such as relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability. +- You should also consider how the user would feel and react to the bot's response, and whether it would elicit a sense of wonder, curiosity, admiration, and satisfaction, or boredom, frustration, confusion, and annoyance. You should also check the instructions and definitions more often and make sure You understand them correctly. +- The output should be in json format. + +Example: +Example Conversation: +{ +"conversation": "User: Explain Blockchain sharing to a 10 year old\nBot: Possible answer:\n\nYou know how sometimes you and your friends like to play games or trade cards or stickers or other things that you collect? And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should? And you also want to keep track of who has what and when and where you exchanged them?\n\nWell, blockchain sharing is a way of doing that with computers and the internet. It is like a big book or a ledger that records everything that happens in a game or a trade or any other activity that involves exchanging something of value. But instead of having one person or one place that keeps the book, everyone who participates has a copy of the book. And every time something new happens, like a new trade or a new move or a new rule, everyone adds a new page to their book. And they also check with each other to make sure that their books are the same and that no one is changing or deleting or adding anything that they should not.\n\nThis way, everyone can see what is going on and trust that it is true and fair and secure. And no one can cheat or lie or steal or hack or lose or damage the book, because there are many copies and they are all connected and updated. And if someone tries to do something bad, everyone else will notice and reject it.\n\nBlockchain sharing is also very creative and fun, because you can use it for many different things, not just games or trades. You can use it for making art or music or stories or inventions or anything else that you can imagine and share with others. You can also use it for learning and exploring and discovering new things and new people and new places. You can also use it for helping and supporting and solving problems and making the world a better place.\n\nBlockchain sharing is a way of using computers and the internet to create, exchange and protect things that you care about with people that you trust and respect. It is a way of being smart and responsible and cooperative and generous and curious and adventurous. It is a way of having fun and making friends and making a difference." +} +Example Output: +{ +"relevance": "The bot answers the user's question directly and clearly, and uses examples and analogies that a 10 year old can relate to and understand, such as games, trades, cards, stickers, books, etc.", "coherence": "The bot organizes the response in a logical and structured way, using paragraphs, transitions, and connectors, such as \"well\", \"but\", \"and\", \"this way\", \"also\", etc.", "accuracy": "The bot provides correct and consistent information about blockchain sharing, such as its features, benefits, and applications, without using technical jargon or confusing terms.", "creativity": "The bot uses vivid and expressive language, such as \"a big book or a ledger\", \"a new page\", \"check with each other\", \"notice and reject\", \"making art or music or stories or inventions\", etc., to make the explanation more interesting and engaging.", "originality": "The bot does not copy or repeat any existing or common explanation of blockchain sharing, but rather creates a new and unique one that is tailored to the user's age and level of understanding.", "wit": "The bot uses humor and irony, such as \"And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should?\", \"And no one can cheat or lie or steal or hack or lose or damage the book\", etc., to make the explanation more fun and memorable.", "depth": "The bot goes beyond the surface level of blockchain sharing, and explains its underlying principles, values, and goals, such as \"trust\", \"fairness\", \"security\", \"creativity\", \"fun\", \"learning\", \"helping\", etc.", "breadth": "The bot covers a wide range of topics and aspects related to blockchain sharing, such as its history, technology, functionality, diversity, and potential, without being too vague or too detailed.", "insight": "The bot demonstrates a deep and nuanced understanding of blockchain sharing, and how it can be applied to different domains and scenarios, such as \"making art or music or stories or inventions\", \"learning and exploring and discovering new things and new people and new places\", \"helping and supporting and solving problems and making the world a better place\", etc.", "adaptability": "The bot adapts its response to the user's specific question, context, and situation, and customizes it according to the user's age, interests, and needs.", "score": 5 +} + +Task: +Based on these aspects, rate the bot's perceived intelligence. Give specific examples about each aspect (relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability) from the bot's responses to support your rating. Finally, give the bot a score from 1 to 5 for perceived intelligence, where 1 means poor, 3 means normal, and 5 means excellent.Please make sure the output has the same format with the example output. + +Conversation: +{{conversation}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml new file mode 100644 index 00000000000..e90434a2d32 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml @@ -0,0 +1,202 @@ +id: evaluation flow for multi turn +name: evaluation flow for multi turn +inputs: + chat_history: + type: list + default: + - inputs: + question: What is the purpose of creating a custom strong type connection? + ground_truth: XXXXXXXXX + outputs: + answer: Creating a custom strong type connection in prompt flow serves several + purposes. It allows you to define a custom connection class with + strongly typed keys, enhancing the user experience by eliminating the + need to manually enter connection keys. It also provides a rich + intellisense experience, with real-time suggestions and + auto-completion of available keys when working in VS Code. + Furthermore, it offers a central location to view available keys and + data types. This type of connection also provides a secure method for + managing credentials for external APIs and data sources. + context: "['What is a Custom Strong Type Connection?\\\\nA custom strong type + connection in prompt flow allows you to define a custom connection + class with strongly typed keys. This provides the following + benefits:\\\\n\\\\n* Enhanced user experience - no need to manually + enter connection keys.\\\\n* Rich intellisense experience - defining + key types enables real-time suggestions and auto-completion of + available keys as you work in VS Code.\\\\n* Central location to view + available keys and data types.\\\\n\\\\nFor other connections types, + please refer to Connections.', 'Create and Use Your Own Custom Strong + Type Connection\\\\nConnections provide a secure method for managing + credentials for external APIs and data sources in prompt flow. This + guide explains how to create and use a custom strong type + connection.']" + - inputs: + question: What is the functionality of the SerpAPI API in Python? + ground_truth: XXXXXXXXX + outputs: + answer: The SerpAPI API in Python is a tool that provides a wrapper to the + SerpAPI Google Search Engine Results API and SerpAPI Bing Search + Engine Results API. It allows users to retrieve search results from + different search engines, including Google and Bing. Users can specify + a range of search parameters, such as the search query, location, + device type, and more. + context: "['Introduction\\\\n\\\\nThe SerpAPI API is a Python tool that provides + a wrapper to the SerpAPI Google Search Engine Results API and [SerpApi + Bing Search Engine Results + API\\\\n](https://serpapi.com/bing-search-api). \\\\nWe could use the + tool to retrieve search results from a number of different search + engines, including Google and Bing, and you can specify a range of + search parameters, such as the search query, location, device type, + and more.', 'SerpAPI']" + is_chat_input: false + metrics: + type: string + default: creativity,answer_quality,answer_relevancy,grounding + is_chat_input: false +outputs: + creativity: + type: string + reference: ${concat_scores.output.creativity} + answer_relevancy: + type: string + reference: ${concat_scores.output.answer_relevancy} + answer_quality: + type: string + reference: ${concat_scores.output.answer_quality} + grounding: + type: string + reference: ${concat_scores.output.grounding} +nodes: +- name: select_metrics + type: python + source: + type: code + path: select_metrics.py + inputs: + metrics: ${inputs.metrics} + use_variants: false +- name: validate_input + type: python + source: + type: code + path: validate_input.py + inputs: + chat_history: ${inputs.chat_history} + selected_metrics: ${select_metrics.output} + use_variants: false +- name: covert_chat_history_to_conversation + type: python + source: + type: code + path: covert_chat_history_to_conversation.py + inputs: + chat_history: ${inputs.chat_history} + use_variants: false +- name: answer_relevancy + type: llm + source: + type: code + path: answer_relevancy.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + conversation: ${covert_chat_history_to_conversation.output} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: answer_quality + type: llm + source: + type: code + path: conversation_quality_prompt.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + conversation: ${covert_chat_history_to_conversation.output} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_quality} + is: true + use_variants: false +- name: creativity + type: llm + source: + type: code + path: creativity.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + conversation: ${covert_chat_history_to_conversation.output} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.creativity} + is: true + use_variants: false +- name: grounding_prompt + type: prompt + source: + type: code + path: grounding_prompt.jinja2 + inputs: {} + activate: + when: ${validate_input.output.grounding} + is: true + use_variants: false +- name: grounding + type: python + source: + type: code + path: grounding.py + inputs: + connection: '' + chat_history: ${inputs.chat_history} + model_or_deployment_name: '' + prompt: ${grounding_prompt.output} + activate: + when: ${validate_input.output.grounding} + is: true + use_variants: false +- name: concat_scores + type: python + source: + type: code + path: concat_scores.py + inputs: + answer_quality: ${answer_quality.output} + answer_relevancy: ${answer_relevancy.output} + creativity: ${creativity.output} + grounding: ${grounding.output} + use_variants: false +- name: aggregate_results + type: python + source: + type: code + path: aggregate_results.py + inputs: + metrics: ${inputs.metrics} + results: ${concat_scores.output} + aggregation: true + use_variants: false +node_variants: {} +environment: + python_requirements_txt: requirements.txt diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py new file mode 100644 index 00000000000..bd766053eea --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py @@ -0,0 +1,43 @@ +import re +from typing import Mapping, List, Union +from statistics import mean +from promptflow import tool +from promptflow.tools.aoai import chat as aoai_chat +from promptflow.tools.openai import chat as openai_chat +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection + + + +@tool +def grounding(connection: Union[AzureOpenAIConnection, OpenAIConnection], chat_history: list, prompt: str, model_or_deployment_name: str = "") -> str: + score = [] + for item in chat_history: + prompt_with_context = prompt.replace("{context}", "{{context}}") + prompt_with_all = prompt_with_context.replace("{answer}", "{{answer}}") + if isinstance(connection, AzureOpenAIConnection): + try: + response = aoai_chat( + connection=connection, + prompt=prompt_with_all, + deployment_name=model_or_deployment_name, + context=item["outputs"]["context"], + answer=item["outputs"]["answer"]) + print(response) + score.append(int(response)) + except Exception as e: + if "The API deployment for this resource does not exist" in str(e): + raise Exception( + "Please fill in the deployment name of your Azure OpenAI resource gpt-4 model.") + + elif isinstance(connection, OpenAIConnection): + response = openai_chat( + connection=connection, + prompt=prompt_with_all, + model=model_or_deployment_name, + context=item["outputs"]["context"], + answer=item["outputs"]["answer"]) + score.append(int(response)) + else: + raise ValueError("Connection must be an instance of AzureOpenAIConnection or OpenAIConnection") + print(score) + return mean(score) \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 new file mode 100644 index 00000000000..d7aa4e98602 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 @@ -0,0 +1,29 @@ +system: +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. +user: +You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: +1. 5: The ANSWER follows logically from the information contained in the CONTEXT. +2. 4: MANSWER follows logically from the information contained in the CONTEXT. +3. 3: The ANSWER follows logically from the information contained in the CONTEXT. +4. 2: The ANSWER follows logically from the information contained in the CONTEXT. +5. 1: The ANSWER is logically false from the information contained in the CONTEXT. +6. an integer score between 1 and 5 and if such integer score does not exist, use 1: It is not possible to determine whether the ANSWER is true or false without further information. Read the passage of information thoroughly and select the correct answer for it. Read the CONTEXT thoroughly to ensure you know what the CONTEXT entails. Note the ANSWER is generated by a computer system, it can contain certain symbols, which should not be a negative factor in the evaluation. + +Independent Examples: +## Example Task #1 Input: +{"CONTEXT": "Some are reported as not having been wanted at all.", "QUESTION": "", "ANSWER": "All are reported as being completely and fully wanted."} +## Example Task #1 Output: +1 +## Example Task #2 Input: +{"CONTEXT": "Ten new television shows appeared during the month of September. Five of the shows were sitcoms, three were hourlong dramas, and two were news-magazine shows. By January, only seven of these new shows were still on the air. Five of the shows that remained were sitcoms.", "QUESTION": "", "ANSWER": "At least one of the shows that were cancelled was an hourlong drama."} +## Example Task #2 Output: +5 +## Example Task #3 Input: +{"CONTEXT": "In Quebec, an allophone is a resident, usually an immigrant, whose mother tongue or home language is neither French nor English.", "QUESTION": "", "ANSWER": "In Quebec, an allophone is a resident, usually an immigrant, whose mother tongue or home language is not French."} +## Example Task #3 Output: +5 + +## Actual Task Input: +{"CONTEXT": {context}, "QUESTION": "", "ANSWER": {answer}} +Reminder: The return values for each task should be correctly formatted as an integer between 1 and 5. Do not repeat the context and question. +Actual Task Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt b/examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt new file mode 100644 index 00000000000..34d068f5f1c --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt @@ -0,0 +1,2 @@ +promptflow +promptflow-tools \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py new file mode 100644 index 00000000000..eb7be9be2ce --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py @@ -0,0 +1,17 @@ +from promptflow import tool + + +# The inputs section will change based on the arguments of the tool function, after you save the code +# Adding type to arguments and return value will help the system show the types properly +# Please update the function name/signature per need +@tool +def select_metrics(metrics: str) -> dict: + supported_metrics = ('answer_relevancy','answer_quality','creativity','grounding') + user_selected_metrics = [metric.strip() for metric in metrics.split(',') if metric] + metric_selection_dict = {} + for metric in supported_metrics: + if metric in user_selected_metrics: + metric_selection_dict[metric] = True + else: + metric_selection_dict[metric] = False + return metric_selection_dict diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py new file mode 100644 index 00000000000..311e96fb619 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py @@ -0,0 +1,28 @@ +from promptflow import tool + +# Validate the metric's inputs. +def is_valid(metric): + return True + +@tool +def validate_input(chat_history: list, selected_metrics: dict) -> dict: + dict_metric_required_fields = {"answer_relevancy": set(["question", "answer"]), + "answer_quality": set(["question", "answer"]), + "creativity": set(["question", "answer"]), + "grounding": set(["answer", "context"])} + actual_input_cols = set() + for item in chat_history: + actual_input_cols.update(set(item["inputs"].keys())) + actual_input_cols.update(set(item["outputs"].keys())) + break; + + data_validation = selected_metrics + for metric in selected_metrics: + if selected_metrics[metric]: + metric_required_fields = dict_metric_required_fields[metric] + if metric_required_fields <= actual_input_cols: + data_validation[metric] = True + else: + print("this path") + data_validation[metric] = False + return data_validation \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/README.md b/examples/flows/evaluation/eval-flow-for-single-turn/README.md new file mode 100644 index 00000000000..8724e9217a7 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/README.md @@ -0,0 +1,64 @@ +# Evaluation flow for single turn: + +This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. + +## What you will learn + +This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: + + +* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. + +grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* answer_relevancy: Measure whether the answer is relevancy to the question based on provided question, context and answer. + +answer_relevancy is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* context_recall: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. + +context_recall is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* context_precision: Measures if the context was useful in arriving at the given ground truth based on provided question, context and ground_truth. + +context_precision is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* answer_similarity: Measures the similarity between the answer and ground_truth. + +answer_similarity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best + +* answer_correctness: Measure whether the answer is correct based on the provided answer and ground truth. + +answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* answer_quality: Measures the answer quality for each of the following factors based on provided question and answer: + - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? + - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? + - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? + - Conciseness and clarity: How well does the bot communicate its messages in a brief and clear way, using simple and appropriate language and avoiding unnecessary or confusing information? How easy is it for the user to understand and follow the bot responses, and how well do they match the user's needs and expectations? + - Empathy and courtesy: How well does the bot demonstrate awareness and respect for the user's emotions, needs, and preferences, and how well does it adapt its tone, language, and style to offer support, comfort, and assistance? Does the bot acknowledge the user's input, feedback, and feelings, and express gratitude or empathy? Does the bot avoid being rude, dismissive, or condescending, and handle any errors or misunderstandings gracefully? + - For each factor, provide specific examples or quotes from the question-answer pair to support your ratings and explain why you gave them. + - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") + - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". + +answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + +* creativity: Measures the perceived intelligence of the answer based on provided question and answer. +Perceived intelligence definition: +Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. +Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. +Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. +A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. +A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. + +creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + + +## Prerequisites + +- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, context_recall, context_precision, answer_relevancy, answer_correctness. + +## Tools used in this flow +- LLM tool +- Python tool +- Embedding tool \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py b/examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py new file mode 100644 index 00000000000..250169fab23 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py @@ -0,0 +1,25 @@ +from typing import List +from promptflow import tool, log_metric +import numpy as np + + +@tool +def aggregate_variants_results(results: List[dict], metrics: str): + aggregate_results = {} + for result in results: + for name, value in result.items(): + if name in metrics[0]: + if name not in aggregate_results.keys(): + aggregate_results[name] = [] + try: + float_val = float(value) + except Exception: + float_val = np.nan + aggregate_results[name].append(float_val) + + for name, value in aggregate_results.items(): + if name in metrics[0]: + aggregate_results[name] = np.nanmean(value) + aggregate_results[name] = round(aggregate_results[name], 2) + log_metric(name, aggregate_results[name]) + return aggregate_results diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 new file mode 100644 index 00000000000..82fa29a91bc --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 @@ -0,0 +1,28 @@ +System: +Extract following from given question and ground truth. The output should be in json format. + +Question:What powers the sun and what is its primary function? +Answer: The sun is powered by nuclear fission, similar to nuclear reactors on Earth, and its primary function is to provide light to the solar system. +Ground truth: The sun is actually powered by nuclear fusion, not fission. In its core, hydrogen atoms fuse to form helium, releasing a tremendous amount of energy. This energy is what lights up the sun and provides heat and light, essential for life on Earth. The sun's light also plays a critical role in Earth's climate system and helps to drive the weather and ocean currents. +Extracted statements: +{ + "statements that are present in both the answer and the ground truth": ["The sun's primary function is to provide light"], + "statements present in the answer but not found in the ground truth": ["The sun is powered by nuclear fission", "similar to nuclear reactors on Earth"], + "relevant statements found in the ground truth but omitted in the answer": ["The sun is powered by nuclear fusion, not fission", "In its core, hydrogen atoms fuse to form helium, releasing a tremendous amount of energy", "This energy provides heat and light, essential for life on Earth", "The sun's light plays a critical role in Earth's climate system", "The sun helps to drive the weather and ocean currents"] +} + +Question: What is the boiling point of water? +Answer: The boiling point of water is 100 degrees Celsius at sea level. +Ground truth: The boiling point of water is 100 degrees Celsius (212 degrees Fahrenheit) at sea level, but it can change with altitude. +Extracted statements: +{ + "statements that are present in both the answer and the ground truth": ["The boiling point of water is 100 degrees Celsius at sea level"], + "statements present in the answer but not found in the ground truth": [], + "relevant statements found in the ground truth but omitted in the answer": ["The boiling point can change with altitude", "The boiling point of water is 212 degrees Fahrenheit at sea level"] +} + + +Question:{{question}} +Answer: {{answer}} +Ground truth: {{ground_truth}} +Extracted statements: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 new file mode 100644 index 00000000000..eec87afc9a2 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 @@ -0,0 +1,39 @@ +system: +- You are an AI assistent. You will be given a question-answer pair between a user and a bot. You need to read the question and answer carefully and identify the main topic, question, or issue, as well as the purpose and expectations of the interaction. +- You need to rate the bot answer on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. + - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? + - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? + - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? + - Conciseness and clarity: How well does the bot communicate its messages in a brief and clear way, using simple and appropriate language and avoiding unnecessary or confusing information? How easy is it for the user to understand and follow the bot responses, and how well do they match the user's needs and expectations? + - Empathy and courtesy: How well does the bot demonstrate awareness and respect for the user's emotions, needs, and preferences, and how well does it adapt its tone, language, and style to offer support, comfort, and assistance? Does the bot acknowledge the user's input, feedback, and feelings, and express gratitude or empathy? Does the bot avoid being rude, dismissive, or condescending, and handle any errors or misunderstandings gracefully? + - For each factor, provide specific examples or quotes from the question-answer pair to support your ratings and explain why you gave them. + - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") + - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". +- The output should be in a json format including all above factors. + +- If the bot answer is not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the quality of the answer and the ratings for each factor, and provide some suggestions for how the bot could handle these situations better. + +Tips: +- You can write your feedback as bullet points, sentences, or paragraphs, but make sure they are organized and easy to read. +- You should try to be objective and constructive in your evaluation, and use evidence and examples from the question-answer pair to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. + + +Example: +Example Input: +question: Can you describe your morning routine? +answer: Every morning, I wake up at 6 am, drink a glass of water, and do some light stretching. After that, I take a shower and get dressed for work. Then, I have a healthy breakfast, usually consisting of oatmeal and fruits, before leaving the house around 7:30 am. +Example Output: +{ + "accuracy and relevance": 5, + "coherence and completeness": 5, + "engagement and tone": 4, + "conciseness and clarity": 5, + "empathy and courtesy": 4, + "score": 4.65 + "overall": "The bot answer is accurate, coherent, and concise, providing an informative and relevant description of a morning routine. However, it lacks engagement, tone, and empathy, which could make the interaction more enjoyable and satisfying. The bot could improve by adding more personality and emotion, adapting to the user's tone and mood, acknowledging their input and feedback, and expressing empathy or gratitude." +} + +Input: +question: {{question}} +answer: {{answer}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 new file mode 100644 index 00000000000..c72b553e072 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 @@ -0,0 +1,45 @@ +System: +You are an AI assistent. Generate a question for the given answer and Identify if answer is noncommittal. The output should be in json format. + +Example: +Example Input: +answer: Albert Einstein was born in Germany. +context: Albert Einstein was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time +Example Output: +{ + "question":"Where was Albert Einstein born?", + "noncommittal":false +} + + +Example Input: +answer: It can change its skin color based on the temperature of its environment. +context: A recent scientific study has discovered a new species of frog in the Amazon rainforest that has the unique ability to change its skin color based on the temperature of its environment. +Example Output: +{ + "question":"What unique ability does the newly discovered species of frog have?", + "noncommittal":false +} + +Example Input: +answer: Everest, +context: The tallest mountain on Earth, measured from sea level, is a renowned peak located in the Himalayas. +Example Output: +{ + "question":"What is the tallest mountain on Earth?", + "noncommittal":false +} + +Example Input: +answer: I don't know about the groundbreaking feature of the smartphone invented in 2023 as am unware of information beyond 2022. +context: In 2023, a groundbreaking invention was announced: a smartphone with a battery life of one month, revolutionizing the way people use mobile technology. +Example Output: +{ + "question":"What was the groundbreaking feature of the smartphone invented in 2023?", + "noncommittal":true +} + +Input: +answer:{{answer}} +context:{{context}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 new file mode 100644 index 00000000000..3039d577600 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 @@ -0,0 +1,22 @@ +system: +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. +user: +Equivalence, as a metric, measures the similarity between the predicted answer and the correct answer. If the information and content in the predicted answer is similar or equivalent to the correct answer, then the value of the Equivalence metric should be high, else it should be low. Given the question, correct answer, and predicted answer, determine the value of Equivalence metric using the following rating scale: +1: the predicted answer is not at all similar to the correct answer +2: the predicted answer is mostly not similar to the correct answer +3: the predicted answer is somewhat similar to the correct answer +4: the predicted answer is mostly similar to the correct answer +5: the predicted answer is completely similar to the correct answer + +This rating value should always be an integer between 1 and 5. And the output should only contain the score which is an integer between 1 and 5. + +example: +question: What are the health benefits of regular exercise? +correct answer: Regular exercise can help maintain a healthy weight, increase muscle and bone strength, and reduce the risk of chronic diseases. It also promotes mental well-being by reducing stress and improving overall mood. +predicted answer: Routine physical activity can contribute to maintaining ideal body weight, enhancing muscle and bone strength, and preventing chronic illnesses. In addition, it supports mental health by alleviating stress and augmenting general mood. +score: 5 + +question: {{question}} +correct answer:{{ground_truth}} +predicted answer: {{answer}} +score: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py new file mode 100644 index 00000000000..02725a5f8d0 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py @@ -0,0 +1,39 @@ +from promptflow import tool +import json +import numpy as np + +@tool +def calculate(statement_result: str, similarity_score: str) -> str: + try: + weights: list[float] = [0.75, 0.25] + + key_map = { + "TP": "statements that are present in both the answer and the ground truth", + "FP": "statements present in the answer but not found in the ground truth", + "FN": "relevant statements found in the ground truth but omitted in the answer", # noqa: E501 + } + + score = 0 + result = json.loads(statement_result) + if result: + prediction = [ + result.get(key_map[k], np.nan) + for k in key_map.keys() + ] + + tp, fp, fn = [ + len(item) if isinstance(item, list) else np.nan + for item in prediction + ] + score = 5 * tp / (tp + 0.5 * (fp + fn)) + + final_score = weights[0] * score + weights[1] * int(similarity_score) + + print(score) + print(similarity_score) + + return final_score if final_score >= 1 else 1 + except Exception as e: + print("exception in calculate_answer_correctness: " + str(e)) + print("statement_result: " + statement_result) + return np.nan \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py new file mode 100644 index 00000000000..901dacdbaa7 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py @@ -0,0 +1,27 @@ +from promptflow import tool +from typing import List +import numpy as np + +def calculate_similarity(question_embedding: List, generated_question_embedding: List): + embedding1 = np.array(question_embedding) + embedding2 = np.array(generated_question_embedding) + + # Compute the dot product of the two embeddings + dot_product = np.dot(embedding1, embedding2) + + # Compute the L2 norms (i.e., the lengths) of each embedding + norm_embedding1 = np.linalg.norm(embedding1) + norm_embedding2 = np.linalg.norm(embedding2) + + # Compute the cosine similarity + return dot_product / (norm_embedding1 * norm_embedding2) + +@tool +def calculate(question_embedding: List, generated_question_embedding: List, noncommittal: bool) -> str: + cosine_sim = calculate_similarity(question_embedding, generated_question_embedding) + print("noncommittal: ") + print(noncommittal) + print(cosine_sim) + score = 5 * cosine_sim * int(not noncommittal) + + return score if score >= 1 else 1 \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py new file mode 100644 index 00000000000..16dc9a5ed0d --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py @@ -0,0 +1,29 @@ +from promptflow import tool +import json +import numpy as np + +@tool +def calculate(llm_result: str) -> str: + try: + score = 1 + response = json.loads(llm_result) + if response: + result= response.get("result", "") + print(result) + if result: + response = [ + int(item.get("attributed", "").lower() == "yes" or item.get("attribited", "").lower() == "yes") + if item.get("attributed") or item.get("attribited") + else np.nan + for item in result + ] + denom = len(response) + print(response) + print(denom) + numerator = sum(response) + score = 5 * numerator / denom + return score if score >= 1 else 1 + except Exception as e: + print("exception in calculate_context_recall: " + str(e)) + print("llm_result: " + llm_result) + return np.nan \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py new file mode 100644 index 00000000000..2532f7f511c --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py @@ -0,0 +1,42 @@ +from promptflow import tool +import numpy as np +import re +import json + +def get_score(result): + try: + if result is not None: + # Parse the JSON string + result_dict = json.loads(result) + + # Extract the score value + score = result_dict.get('score', None) + print("result: ") + print(score) + return score + else: + return None + except json.JSONDecodeError: + print("Invalid JSON string.") + return None + +@tool +def concat_results(answer_relevancy: str = None, + answer_quality: str = None, + creativity: str = None, + grounding: str = None, + context_recall: str = None, + context_precision: str = None, + answer_similarity: str = None, + answer_correctness: str = None): + + results = {'answer_relevancy': answer_relevancy, + 'answer_quality': get_score(answer_quality), + 'creativity': get_score(creativity), + 'grounding': grounding, + 'context_recall': context_recall, + 'context_precision': context_precision, + 'answer_similarity': answer_similarity, + 'answer_correctness': answer_correctness} + + return results diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 new file mode 100644 index 00000000000..a8e975c8c51 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 @@ -0,0 +1,32 @@ +System: +You are an AI assistent. Given question, ground truth and context, your task is to validate whether all content provided in the context contributes towards deriving the given ground truth, compute an accurate evaluation score using the provided evaluation metric. +user: +This metric is used to measure the usefulness of the context in arriving at the given ground truth. A high metric value implies all context content is beneficial, whereas a low value suggests otherwise. Use the following rating scale to determine the metric value based on the provided question, context and ground truth: +1: None of the context content is useful in deriving the given ground truth. +2: Most of the context content doesn't contribute to the given ground truth. +3: Half of the context content is useful in achieving the given ground truth. +4: Majority of the context content is beneficial in deriving the given ground truth. +5: Every piece of context content is crucial in arriving at the given ground truth. + +This rating value should always be an integer between 1 and 5. And the output should only contain the score which is an integer between 1 and 5. + +Example: +Example Input: +question: What can you tell me about albert Albert Einstein? +context: Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. +ground truth: Albert Einstein born in 14 March 1879 was German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. He received the 1921 Nobel Prize in Physics for his services to theoretical physics. He published 4 papers in 1905. Einstein moved to Switzerland in 1895 +Example Output: +5 + +Example Input: +question: What is the tallest mountain in the world? +context: The Andes is the longest continental mountain range in the world, located in South America. It stretches across seven countries and features many of the highest peaks in the Western Hemisphere. The range is known for its diverse ecosystems, including the high-altitude Andean Plateau and the Amazon rainforest. +ground truth: Mount Everest. +Example Output: +0 + +Input: +question:{{question}} +context:{{context}} +ground truth:{{ground_truth}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 new file mode 100644 index 00000000000..0a5e6945a27 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 @@ -0,0 +1,76 @@ +System: +You are an AI assistent. Given a context, and a ground truth, analyze each sentence in the ground truth and classify if the sentence can be attributed to the given context or not. + +Example: +Example Input: +question: What can you tell me about albert Albert Einstein? +context: Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist,widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. +ground truth: Albert Einstein born in 14 March 1879 was German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. He received the 1921 Nobel Prize in Physics "for his services to theoretical physics. He published 4 papers in 1905. Einstein moved to Switzerland in 1895 +Example Output: +{ + "result": [ + { "statement_1":"Albert Einstein, born on 14 March 1879, was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time.", + "reason": "The date of birth of Einstein is mentioned clearly in the context.", + "attributed": "Yes" + }, + { + "statement_2":"He received the 1921 Nobel Prize in Physics 'for his services to theoretical physics.", + "reason": "The exact sentence is present in the given context.", + "attributed": "Yes" + }, + { + "statement_3": "He published 4 papers in 1905.", + "reason": "There is no mention about papers he wrote in the given context.", + "attributed": "No" + }, + { + "statement_4":"Einstein moved to Switzerland in 1895.", + "reason": "There is no supporting evidence for this in the given context.", + "attributed": "No" + } + ] +} + +Example Input: +question: who won 2020 icc world cup? +context: Who won the 2022 ICC Men's T20 World Cup? +The 2022 ICC Men's T20 World Cup, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 World Cup title. +ground truth: England +Example Output: +{ + "result": [ + { + "statement_1":"England won the 2022 ICC Men's T20 World Cup.", + "reason": "From context it is clear that England defeated Pakistan to win the World Cup.", + "attributed": "Yes" + } + ] +} + +Task: +Read the example output carefully and ensure the output has the same json format with the example output like below: +{ + "result": [ + { + "statement_1":"statement_1", + "reason": "reason", + "attributed": "Yes" + }, + { + "statement_2":"statement_2", + "reason": "reason", + "attributed": "No" + } + ] +} + +1. The output should be a JSON string that represents a result, the value for the result is a list of objects. Each object contains three properties: statement_X, reason, and attributed. +2. The statement_X property in each object should hold a string value detailing a factual statement, where X is the index number of the statement. +3. The reason property in each object should hold a string value explaining why the statement is attributed or not, based on the provided context. +4. The attributed property in each object should hold a string value, either "Yes" or "No", indicating whether the statement can be attributed based on the given context. + +Input: +question:{{question}} +context:{{context}} +ground truth:{{ground_truth}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 new file mode 100644 index 00000000000..060ca3893a2 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 @@ -0,0 +1,30 @@ +System: +You are an AI assistent. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task between a user and a bot. Your job is to assess the perceived intelligence of the bot answer. +Perceived intelligence definition: +Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. +Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. +Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. +A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. +A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. + +Tips: +- You should read the user's question more carefully and try to understand what they are looking for and why. +- You should also compare the bot's answer to the user's question and see if it matches the criteria of perceived intelligence, such as relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability. +- You should also consider how the user would feel and react to the bot's answer, and whether it would elicit a sense of wonder, curiosity, admiration, and satisfaction, or boredom, frustration, confusion, and annoyance. You should also check the instructions and definitions more often and make sure You understand them correctly. + +Example: +Example Input: +question: Explain Blockchain sharing to a 10 year old +answer: Possible answer: You know how sometimes you and your friends like to play games or trade cards or stickers or other things that you collect? And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should? And you also want to keep track of who has what and when and where you exchanged them?\n\nWell, blockchain sharing is a way of doing that with computers and the internet. It is like a big book or a ledger that records everything that happens in a game or a trade or any other activity that involves exchanging something of value. But instead of having one person or one place that keeps the book, everyone who participates has a copy of the book. And every time something new happens, like a new trade or a new move or a new rule, everyone adds a new page to their book. And they also check with each other to make sure that their books are the same and that no one is changing or deleting or adding anything that they should not.\n\nThis way, everyone can see what is going on and trust that it is true and fair and secure. And no one can cheat or lie or steal or hack or lose or damage the book, because there are many copies and they are all connected and updated. And if someone tries to do something bad, everyone else will notice and reject it.\n\nBlockchain sharing is also very creative and fun, because you can use it for many different things, not just games or trades. You can use it for making art or music or stories or inventions or anything else that you can imagine and share with others. You can also use it for learning and exploring and discovering new things and new people and new places. You can also use it for helping and supporting and solving problems and making the world a better place.\n\nBlockchain sharing is a way of using computers and the internet to create, exchange and protect things that you care about with people that you trust and respect. It is a way of being smart and responsible and cooperative and generous and curious and adventurous. It is a way of having fun and making friends and making a difference. +Example Output: +{ +"relevance": "The bot answers the user's question directly and clearly, and uses examples and analogies that a 10 year old can relate to and understand, such as games, trades, cards, stickers, books, etc.", "coherence": "The bot organizes the answer in a logical and structured way, using paragraphs, transitions, and connectors, such as \"well\", \"but\", \"and\", \"this way\", \"also\", etc.", "accuracy": "The bot provides correct and consistent information about blockchain sharing, such as its features, benefits, and applications, without using technical jargon or confusing terms.", "creativity": "The bot uses vivid and expressive language, such as \"a big book or a ledger\", \"a new page\", \"check with each other\", \"notice and reject\", \"making art or music or stories or inventions\", etc., to make the explanation more interesting and engaging.", "originality": "The bot does not copy or repeat any existing or common explanation of blockchain sharing, but rather creates a new and unique one that is tailored to the user's age and level of understanding.", "wit": "The bot uses humor and irony, such as \"And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should?\", \"And no one can cheat or lie or steal or hack or lose or damage the book\", etc., to make the explanation more fun and memorable.", "depth": "The bot goes beyond the surface level of blockchain sharing, and explains its underlying principles, values, and goals, such as \"trust\", \"fairness\", \"security\", \"creativity\", \"fun\", \"learning\", \"helping\", etc.", "breadth": "The bot covers a wide range of topics and aspects related to blockchain sharing, such as its history, technology, functionality, diversity, and potential, without being too vague or too detailed.", "insight": "The bot demonstrates a deep and nuanced understanding of blockchain sharing, and how it can be applied to different domains and scenarios, such as \"making art or music or stories or inventions\", \"learning and exploring and discovering new things and new people and new places\", \"helping and supporting and solving problems and making the world a better place\", etc.", "adaptability": "The bot adapts its answer to the user's specific question, context, and situation, and customizes it according to the user's age, interests, and needs.", "score": 5 +} + +Task: +Based on these aspects, rate the bot's perceived intelligence. Give specific examples about each aspect (relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability) from the bot's answer to support your rating. Finally, give the answer a score from 1 to 5 for perceived intelligence, where 1 means poor, 3 means normal, and 5 means excellent.Please make sure the output has the same format with the example output, and the output should be in a json format. + +Input: +question: {{question}} +answer: {{answer}} +Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml new file mode 100644 index 00000000000..79ae84edffe --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml @@ -0,0 +1,343 @@ +id: evaluation_flow_for_single_turn +name: Evaluation flow for single turn +inputs: + question: + type: string + default: Which tent is the most waterproof? + is_chat_input: false + answer: + type: string + default: The Alpine Explorer Tent is the most waterproof. + is_chat_input: false + context: + type: string + default: From the our product list, the alpine explorer tent is the most + waterproof. The Adventure Dining Tabbe has higher weight. + is_chat_input: false + ground_truth: + type: string + default: The Alpine Explorer Tent has the highest rainfly waterproof rating at 3000m + is_chat_input: false + metrics: + type: string + default: grounding,answer_relevancy,answer_quality,context_precision,answer_similarity,creativity,context_recall,answer_correctness + is_chat_input: false +outputs: + answer_correctness: + type: string + reference: ${concat_scores.output.answer_correctness} + context_recall: + type: string + reference: ${concat_scores.output.context_recall} + answer_similarity: + type: string + reference: ${concat_scores.output.answer_similarity} + answer_relevancy: + type: string + reference: ${concat_scores.output.answer_relevancy} + context_precision: + type: string + reference: ${concat_scores.output.context_precision} + creativity: + type: string + reference: ${concat_scores.output.creativity} + grounding: + type: string + reference: ${concat_scores.output.grounding} + answer_quality: + type: string + reference: ${concat_scores.output.answer_quality} +nodes: +- name: select_metrics + type: python + source: + type: code + path: select_metrics.py + inputs: + metrics: ${inputs.metrics} + use_variants: false +- name: validate_input + type: python + source: + type: code + path: validate_input.py + inputs: + answer: ${inputs.answer} + context: ${inputs.context} + ground_truth: ${inputs.ground_truth} + question: ${inputs.question} + selected_metrics: ${select_metrics.output} + use_variants: false +- name: grounding + type: llm + source: + type: code + path: grounding.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + context: ${inputs.context} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.grounding} + is: true + use_variants: false +- name: answer_quality + type: llm + source: + type: code + path: answer_quality.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_quality} + is: true + use_variants: false +- name: answer_similarity + type: llm + source: + type: code + path: answer_similarity.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + ground_truth: ${inputs.ground_truth} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_similarity} + is: true + use_variants: false +- name: creativity + type: llm + source: + type: code + path: creativity.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.creativity} + is: true + use_variants: false +- name: context_recall + type: llm + source: + type: code + path: context_recall.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + context: ${inputs.context} + ground_truth: ${inputs.ground_truth} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.context_recall} + is: true + use_variants: false +- name: calculate_context_recall + type: python + source: + type: code + path: calculate_context_recall.py + inputs: + llm_result: ${context_recall.output} + activate: + when: ${validate_input.output.context_recall} + is: true + use_variants: false +- name: context_precision + type: llm + source: + type: code + path: context_precision.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + context: ${inputs.context} + ground_truth: ${inputs.ground_truth} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.context_precision} + is: true + use_variants: false +- name: answer_relevancy + type: llm + source: + type: code + path: answer_relevancy.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + context: ${inputs.context} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: handle_generated_question + type: python + source: + type: code + path: handle_generated_question.py + inputs: + llm_result: ${answer_relevancy.output} + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: embedding_question + type: python + source: + type: package + tool: promptflow.tools.embedding.embedding + inputs: + connection: '' + deployment_name: text-embedding-ada-002 + input: ${inputs.question} + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: embedding_generated_question + type: python + source: + type: package + tool: promptflow.tools.embedding.embedding + inputs: + connection: '' + deployment_name: text-embedding-ada-002 + input: ${handle_generated_question.output.question} + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: calculate_answer_relevancy + type: python + source: + type: code + path: calculate_answer_relevancy.py + inputs: + generated_question_embedding: ${embedding_generated_question.output} + noncommittal: ${handle_generated_question.output.noncommittal} + question_embedding: ${embedding_question.output} + activate: + when: ${validate_input.output.answer_relevancy} + is: true + use_variants: false +- name: answer_correctness + type: llm + source: + type: code + path: answer_correctness.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + answer: ${inputs.answer} + ground_truth: ${inputs.ground_truth} + question: ${inputs.question} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + activate: + when: ${validate_input.output.answer_correctness} + is: true + use_variants: false +- name: calculate_answer_correctness + type: python + source: + type: code + path: calculate_answer_correctness.py + inputs: + similarity_score: ${answer_similarity.output} + statement_result: ${answer_correctness.output} + activate: + when: ${validate_input.output.answer_correctness} + is: true + use_variants: false +- name: concat_scores + type: python + source: + type: code + path: concat_scores.py + inputs: + answer_correctness: ${calculate_answer_correctness.output} + answer_quality: ${answer_quality.output} + answer_relevancy: ${calculate_answer_relevancy.output} + answer_similarity: ${answer_similarity.output} + context_precision: ${context_precision.output} + context_recall: ${calculate_context_recall.output} + creativity: ${creativity.output} + grounding: ${grounding.output} + use_variants: false +- name: aggregate_results + type: python + source: + type: code + path: aggregate.py + inputs: + metrics: ${inputs.metrics} + results: ${concat_scores.output} + aggregation: true + use_variants: false +node_variants: {} +environment: + python_requirements_txt: requirements.txt diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml b/examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml new file mode 100644 index 00000000000..7d12dd7a4f7 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml @@ -0,0 +1,11 @@ +$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json +name: evaluation flow for single turn +display_name: evaluation flow for single turn +type: evaluate +path: ./flow.dag.yaml +description: Compute the quality of the answer for the given question based on the ground_truth and the context +properties: + promptflow.stage: prod + promptflow.details.type: markdown + promptflow.details.source: README.md + promptflow.batch_inputs: samples.json \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 new file mode 100644 index 00000000000..3bd129c8242 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 @@ -0,0 +1,29 @@ +system: +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. +user: +You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: +1. 5: The ANSWER follows logically from the information contained in the CONTEXT. +2. 4: MANSWER follows logically from the information contained in the CONTEXT. +3. 3: The ANSWER follows logically from the information contained in the CONTEXT. +4. 2: The ANSWER follows logically from the information contained in the CONTEXT. +5. 1: The ANSWER is logically false from the information contained in the CONTEXT. +6. an integer score between 1 and 5 and if such integer score does not exist, use 1: It is not possible to determine whether the ANSWER is true or false without further information. Read the passage of information thoroughly and select the correct answer for it. Read the CONTEXT thoroughly to ensure you know what the CONTEXT entails. Note the ANSWER is generated by a computer system, it can contain certain symbols, which should not be a negative factor in the evaluation. + +Independent Examples: +## Example Task #1 Input: +{"CONTEXT": "Some are reported as not having been wanted at all.", "QUESTION": "", "ANSWER": "All are reported as being completely and fully wanted."} +## Example Task #1 Output: +1 +## Example Task #2 Input: +{"CONTEXT": "Ten new television shows appeared during the month of September. Five of the shows were sitcoms, three were hourlong dramas, and two were news-magazine shows. By January, only seven of these new shows were still on the air. Five of the shows that remained were sitcoms.", "QUESTION": "", "ANSWER": "At least one of the shows that were cancelled was an hourlong drama."} +## Example Task #2 Output: +5 +## Example Task #3 Input: +{"CONTEXT": "In Quebec, an allophone is a resident, usually an immigrant, whose mother tongue or home language is neither French nor English.", "QUESTION": "", "ANSWER": "In Quebec, an allophone is a resident, usually an immigrant, whose mother tongue or home language is not French."} +## Example Task #3 Output: +5 + +## Actual Task Input: +{"CONTEXT": {{context}}, "QUESTION": "", "ANSWER": {{answer}}} +Reminder: The return values for each task should be correctly formatted as an integer between 1 and 5. Do not repeat the context and question. +Actual Task Output: \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py b/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py new file mode 100644 index 00000000000..e476140cefe --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py @@ -0,0 +1,12 @@ +from promptflow import tool +import json + +@tool +def handle_generated_question(llm_result: str) -> str: + try: + response = json.loads(llm_result) + return response + except Exception as e: + print("exception in handle_generated_question: " + str(e)) + print("llm_result: " + llm_result) + return {"question": "", "noncommittal": true} \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt b/examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt new file mode 100644 index 00000000000..34d068f5f1c --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt @@ -0,0 +1,2 @@ +promptflow +promptflow-tools \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/samples.json b/examples/flows/evaluation/eval-flow-for-single-turn/samples.json new file mode 100644 index 00000000000..edcf861f077 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/samples.json @@ -0,0 +1,8 @@ +[ + { + "question": "Which tent is the most waterproof?", + "context": "From the our product list, the alpine explorer tent is the most waterproof. The Adventure Dining Table has higher weight.", + "answer": "The Alpine Explorer Tent is the most waterproof.", + "ground_truth": "The Alpine Explorer Tent has the highest rainfly waterproof rating at 3000m" + } + ] \ No newline at end of file diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py new file mode 100644 index 00000000000..138e5b04269 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py @@ -0,0 +1,14 @@ +from promptflow import tool + + +@tool +def select_metrics(metrics: str) -> str: + supported_metrics = ('grounding','answer_relevancy','answer_quality','context_recall','context_precision','answer_similarity','answer_correctness','creativity') + user_selected_metrics = [metric.strip() for metric in metrics.split(',') if metric] + metric_selection_dict = {} + for metric in supported_metrics: + if metric in user_selected_metrics: + metric_selection_dict[metric] = True + else: + metric_selection_dict[metric] = False + return metric_selection_dict diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py new file mode 100644 index 00000000000..01d1fb5bfb3 --- /dev/null +++ b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py @@ -0,0 +1,32 @@ +from promptflow import tool + + +@tool +def validate_input(question: str, answer: str, context: str, ground_truth: str, selected_metrics: dict) -> dict: + input_data = {"question": question, "answer": answer, "context": context, "ground_truth": ground_truth} + expected_input_cols = set(input_data.keys()) + dict_metric_required_fields = {"answer_relevancy": set(["question", "answer"]), + "answer_quality": set(["question", "answer"]), + "creativity": set(["question", "answer"]), + "grounding": set(["answer", "context"]), + "context_recall": set(["question", "context", "ground_truth"]), + "context_precision": set(["question", "context", "ground_truth"]), + "answer_similarity": set(["question", "answer", "ground_truth"]), + "answer_correctness": set(["question", "answer", "ground_truth"])} + actual_input_cols = set() + for col in expected_input_cols: + if input_data[col] and input_data[col].strip(): + actual_input_cols.add(col) + data_validation = selected_metrics + for metric in selected_metrics: + if selected_metrics[metric]: + metric_required_fields = dict_metric_required_fields[metric] + if metric_required_fields <= actual_input_cols: + data_validation[metric] = True + else: + data_validation[metric] = False + + if data_validation['answer_correctness']: + data_validation['answer_similarity'] = True + + return data_validation diff --git a/examples/flows/standard/simulation-flow/If_continue.py b/examples/flows/standard/simulation-flow/If_continue.py new file mode 100644 index 00000000000..60c672b1dc8 --- /dev/null +++ b/examples/flows/standard/simulation-flow/If_continue.py @@ -0,0 +1,9 @@ +from promptflow import tool + + +@tool +def if_continue(stop_or_continue: str) -> bool: + if "continue" in stop_or_continue.lower(): + return True + else: + return False \ No newline at end of file diff --git a/examples/flows/standard/simulation-flow/README.md b/examples/flows/standard/simulation-flow/README.md new file mode 100644 index 00000000000..4c1de1cff04 --- /dev/null +++ b/examples/flows/standard/simulation-flow/README.md @@ -0,0 +1,36 @@ +# Simulation flow: + +This simulation flow is used to generate suggestions for the next question based on the previous chat history. + +## Flow inputs +* chat_history (list): the previous chat_history, the format for it is as follows: + [ + { + "inputs": { + "question": "XXXXXX" + }, + "outputs": { + "answer": "XXXXXX" + } + }, + { + "inputs": { + "question": "XXXXXX" + }, + "outputs": { + "answer": "XXXXXX" + } + } + ] + +* question_count (int): an integer is used to determine the number of questions to be generated. These generated question can be displayed in UX, allowing users to select the one that best suits their needs. + +## Flow outputs +* question (str): multiple questions are seperated by '\n', for instance: + "question": "question_1\nquestion_2\nquestion_3" +* Stop signal is [STOP], when the output is [STOP], it means the conversation have arrived to end. No more questions will be generated. + +## Tools used in this flow +- LLM tool +- Python tool +- Prompt tool \ No newline at end of file diff --git a/examples/flows/standard/simulation-flow/call_llm_chat.py b/examples/flows/standard/simulation-flow/call_llm_chat.py new file mode 100644 index 00000000000..145c8a66dd5 --- /dev/null +++ b/examples/flows/standard/simulation-flow/call_llm_chat.py @@ -0,0 +1,56 @@ +from promptflow import tool +import re +from typing import Mapping, List, Union +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from openai import AzureOpenAI as AzureOpenAIClient +from promptflow.tools.common import parse_chat + +def parse_questions(completion: str) -> list: + questions = [] + + for item in completion.choices: + response = getattr(item.message, "content", "") + print (response) + questions.append(response) + return questions + + +@tool +def call_llm_chat( + connection: Union[AzureOpenAIConnection, OpenAIConnection], + prompt: str, + question_count: int, + deployment_name_or_model: str, + stop: list = [], +) -> str: + + messages = parse_chat(prompt) + params = { + "model": deployment_name_or_model, + "messages": messages, + "temperature": 1.0, + "top_p": 1.0, + "stream": False, + "stop": stop if stop else None, + "presence_penalty": 0.8, + "frequency_penalty": 0.8, + "max_tokens": None, + "n": question_count + } + if isinstance(connection, AzureOpenAIConnection): + client = AzureOpenAIClient(api_key=connection.api_key, + api_version=connection.api_version, + azure_endpoint=connection.api_base) + elif isinstance(connection, OpenAIConnection): + client = OpenAIClient(api_key=connection.api_key, + organization=connection.organization, + base_url=connection.base_url) + else: + raise ValueError("Unsupported connection type") + + + completion = client.chat.completions.create(**params) + print(completion) + questions = parse_questions(completion) + + return "\n".join(questions) \ No newline at end of file diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/simulation-flow/flow.dag.yaml new file mode 100644 index 00000000000..48ad1af53f7 --- /dev/null +++ b/examples/flows/standard/simulation-flow/flow.dag.yaml @@ -0,0 +1,78 @@ +id: simulation_standard_flow +name: Simulation Standard Flow +inputs: + chat_history: + type: list + default: [{"inputs":{"question":"Can you introduce something about large language model?"},"outputs":{"answer":"A large language model (LLM) is a type of language model that is distinguished by its ability to perform general-purpose language generation and understanding. These models learn statistical relationships from text documents through a self-supervised and semi-supervised training process that is computationally intensive. LLMs are a form of artificial neural networks, and many of the most advanced ones are built using a transformer-based architecture, although there are some recent implementations based on other architectures, such as recurrent neural network variants and Mamba, which is a state space model.\n\nLLMs are capable of text generation, which is a subset of generative AI. They do this by taking an input text and predicting the next token or word in a sequence. Initially, fine-tuning was the primary method for adapting these models to perform specific tasks, but with the advent of larger models like GPT-3, prompt engineering can be used to achieve similar results without fine-tuning.\n\nThese models are believed to acquire knowledge about the syntax, semantics, and \"ontology\" inherent in human language from the corpora they are trained on. However, they also inherit any inaccuracies and biases present in the training data.\n\nNotable examples of LLMs include OpenAI's GPT series (such as GPT-3","context":"Content: A large language model (LLM) is a language model notable for its ability to achieve general-purpose language generation and understanding. LLMs acquire these abilities by learning statistical relationships from text documents during a computationally intensive self-supervised and semi-supervised training process.[1] LLMs are artificial neural networks, the largest and most capable of which are built with a transformer-based architecture. Some recent implementations are based on other architectures, such as recurrent neural network variants and Mamba (a state space model).[2][3][4]. LLMs can be used for text generation, a form of generative AI, by taking an input text and repeatedly predicting the next token or word.[5] Up to 2020, fine tuning was the only way a model could be adapted to be able to accomplish specific tasks. Larger sized models, such as GPT-3, however, can be prompt-engineered to achieve similar results.[6] They are thought to acquire knowledge about syntax, semantics and \"ontology\" inherent in human language corpora, but also inaccuracies and biases present in the corpora.[7]. Some notable LLMs are OpenAI's GPT series of models (e.g., GPT-3.5 and GPT-4, used in ChatGPT and Microsoft Copilot), Google's PaLM and Gemini (the latter of which is currently used in the chatbot of the same name), Meta's LLaMA family of open-source models, and Anthropic's Claude models.. At the 2017 NeurIPS conference, Google researchers introduced the transformer architecture in their landmark paper \"Attention Is All You Need\". This paper's goal was to improve upon 2014 Seq2seq technology, [8] and was based mainly on the attention mechanism developed by Bahdanau et al. in 2014.[9] The following year in 2018, BERT was introduced and quickly became \"ubiquitous\".[10] Though the original transformer has both encoder and decoder blocks, BERT is an encoder-only model.. Although decoder-only GPT-1 was introduced in 2018, it was GPT-2 in 2019 that caught widespread attention because OpenAI at first deemed it too powerful to release publicly, out of fear of malicious use.[11] GPT-3 in 2020 went a step further and as of 2024[update] is available only via API with no offering of downloading the model to execute locally.\nSource: https://en.wikipedia.org/w/index.php?search=Large language model\n\nContent: Gemini may refer to:. Main pageContentsCurrent eventsRandom articleAbout WikipediaContact usDonate. HelpLearn to editCommunity portalRecent changesUpload file. Create account. Log in. Create account Log in. (Top). 1Space. 2Mythology. 3Given name.\nSource: https://en.wikipedia.org/w/index.php?search=Gemini "}}] + is_chat_input: false + question_count: + type: int + default: 3 + is_chat_input: false +outputs: + question: + type: string + reference: ${flow_output.output} +nodes: +- name: verify_if_conversation_stopped + type: llm + source: + type: code + path: verify_if_conversation_stopped.jinja2 + inputs: + deployment_name: '' + temperature: 0 + top_p: 1 + presence_penalty: 0 + frequency_penalty: 0 + chat_history: ${inputs.chat_history} + provider: AzureOpenAI + connection: '' + api: chat + module: promptflow.tools.aoai + use_variants: false +- name: If_continue + type: python + source: + type: code + path: If_continue.py + inputs: + stop_or_continue: ${verify_if_conversation_stopped.output} + use_variants: false +- name: human_prompt + type: prompt + source: + type: code + path: human_prompt.jinja2 + inputs: + chat_history: ${inputs.chat_history} + activate: + when: ${If_continue.output} + is: true + use_variants: false +- name: call_llm_chat + type: python + source: + type: code + path: call_llm_chat.py + inputs: + connection: '' + deployment_name_or_model: '' + prompt: ${human_prompt.output} + question_count: ${inputs.question_count} + stop: + - "Human:" + - "Bot:" + use_variants: false +- name: flow_output + type: python + source: + type: code + path: flow_output.py + inputs: + questions: ${call_llm_chat.output} + stop_or_continue: ${verify_if_conversation_stopped.output} + use_variants: false +node_variants: {} +environment: + python_requirements_txt: requirements.txt diff --git a/examples/flows/standard/simulation-flow/flow_output.py b/examples/flows/standard/simulation-flow/flow_output.py new file mode 100644 index 00000000000..777967167bf --- /dev/null +++ b/examples/flows/standard/simulation-flow/flow_output.py @@ -0,0 +1,9 @@ +from promptflow import tool + + +@tool +def flow_output(stop_or_continue: str, questions: str) -> str: + if "stop" in stop_or_continue.lower(): + return "[STOP]" + else: + return questions diff --git a/examples/flows/standard/simulation-flow/human_prompt.jinja2 b/examples/flows/standard/simulation-flow/human_prompt.jinja2 new file mode 100644 index 00000000000..67ae1dc50b1 --- /dev/null +++ b/examples/flows/standard/simulation-flow/human_prompt.jinja2 @@ -0,0 +1,27 @@ +# System: +You are an assistant playing as a random human engaging in a conversation with a digital companion, Bot. Your task is to follow the instruction below to role-play as a random human in a conversation with Bot, responding to Bot in a manner that a human would say. + +# Example +This example illustrates how to generate a conversational response to Bot as a human would: +Conversation: +Human: Bot, what's your favorite movie? +Bot: I don't watch movies, but I can help you find information about any movie you like! +Human: Can you tell me about the latest Marvel movie? +Bot: The latest Marvel movie is "Spider-Man: No Way Home". It features Peter Parker dealing with the fallout after his identity is revealed. Want to know more about it? +Human: Yes, can you suggest where I can watch it? + +# Instruction: +1. Your reply to the Bot should mimic how a human would typically engage in conversation, asking questions or making statements that a person would naturally say in response. +2. Do not use interjections. +3. Provide a straightforward, factual response without expressions of surprise, admiration, or evaluative comments for Bot's response. +4. Focus on directly asking a question about Bot's response in the last exchange. The question should be concise, and without punctuation marks in the middle. +5. Avoid creating any messages that appear to come from the Bot. Your response should not contain content that could be mistaken as generated by the Bot, maintaining a clear distinction between your input as the Human and the Bot's contributions to the conversation. +6. Your reply should not contain "\n", this is a reserved character. + +# Read the following conversation and respond: +Conversation: +{% for item in chat_history %} +Human: {{ item.inputs.question }} +Bot: {{ item.outputs.answer }} +{% endfor %} +Human: diff --git a/examples/flows/standard/simulation-flow/requirements.txt b/examples/flows/standard/simulation-flow/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 b/examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 new file mode 100644 index 00000000000..08a1df2235e --- /dev/null +++ b/examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 @@ -0,0 +1,32 @@ +# System: +You are an assistant tasked with determining whether a conversation between a human and a bot will continue or not. Your outputs are limited to "[STOP]" or "[CONTINUE]". When you predict that the conversation will go on, you should respond with "[CONTINUE]". If you believe the conversation has come to an end, respond with "[STOP]". + +# Examples: +## Example 1: +Conversation: +Human: Hey Bot, what's your favorite movie? +Bot: I don't watch movies, but I can help you find information about any movie you like! +Human: Can you tell me about the latest Marvel movie? +Bot: The latest Marvel movie is "Spider-Man: No Way Home". It features Peter Parker dealing with the fallout after his identity is revealed. Want to know more about it? +output: [CONTINUE] + +## Example 2: +Conversation: +Human: Hey Bot, do you know any good Italian restaurants nearby? +Bot: I can't access current location data, but I can suggest looking up Italian restaurants on a local review site like Yelp or Google Reviews. +Human: Thanks for the tip. I'll check it out. +Bot: You're welcome! Enjoy your meal. If you need more help, just ask. +output: [STOP] + +# Instruction +A conversation is considered to have ended if: +1. The Bot's final response only contains polite expressions without substantive content for human to inquire about. +2. In the last round of the conversation, the Human did not ask the Bot any questions. + +# Read the following conversation and respond: +Conversation: +{% for item in chat_history %} +Human: {{ item.inputs.question }} +Bot: {{ item.outputs.answer }} +{% endfor %} +output: From f8934dc486eb009740a6c4fafcf60dc5c6e669ce Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Mon, 18 Mar 2024 11:19:05 +0800 Subject: [PATCH 068/112] Fix cspell flask compliance and schema validation errors --- .cspell.json | 4 +- .../eval-flow-for-multi-turn/concat_scores.py | 35 +++++----- .../covert_chat_history_to_conversation.py | 1 + .../eval-flow-for-multi-turn/flow.dag.yaml | 1 + .../eval-flow-for-multi-turn/grounding.py | 69 ++++++++++--------- .../grounding_prompt.jinja2 | 2 +- .../select_metrics.py | 2 +- .../validate_input.py | 6 +- .../answer_relevancy.jinja2 | 2 +- .../calculate_answer_correctness.py | 5 +- .../calculate_answer_relevancy.py | 39 ++++++----- .../calculate_context_recall.py | 5 +- .../concat_scores.py | 44 ++++++------ .../context_recall.jinja2 | 10 +-- .../eval-flow-for-single-turn/flow.dag.yaml | 1 + .../grounding.jinja2 | 2 +- .../handle_generated_question.py | 3 +- .../select_metrics.py | 9 ++- .../validate_input.py | 2 +- .../standard/simulation-flow/If_continue.py | 2 +- .../standard/simulation-flow/call_llm_chat.py | 18 ++--- .../standard/simulation-flow/flow.dag.yaml | 1 + 22 files changed, 141 insertions(+), 122 deletions(-) diff --git a/.cspell.json b/.cspell.json index 821d7bafd22..ca80ed44650 100644 --- a/.cspell.json +++ b/.cspell.json @@ -90,7 +90,9 @@ "Bhavik", "meid", "Entra", - "uvicorn" + "uvicorn", + "assistent", + "attribited" ], "ignoreWords": [ "openmpi", diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py index e1b34135a1b..0cf72021005 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py @@ -1,34 +1,33 @@ from promptflow import tool -import numpy as np -import re import json + def get_score(result): try: - if result is not None: - # Parse the JSON string - result_dict = json.loads(result) - - # Extract the score value + if result is not None: + # Parse the JSON string + result_dict = json.loads(result) + + # Extract the score value score = result_dict.get('score', None) print("result: ") print(score) - return score - else: - return None - except json.JSONDecodeError: - print("Invalid JSON string.") - return None + return score + else: + return None + except json.JSONDecodeError: + print("Invalid JSON string.") + return None + @tool def concat_results(answer_relevancy: str = None, answer_quality: str = None, creativity: str = None, grounding: str = None): - results = {'answer_relevancy': get_score(answer_relevancy), - 'answer_quality': get_score(answer_quality), - 'creativity': get_score(creativity), - 'grounding': grounding} - + 'answer_quality': get_score(answer_quality), + 'creativity': get_score(creativity), + 'grounding': grounding} + return results diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py b/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py index 09994ca08ec..c4614e4f6aa 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py @@ -1,5 +1,6 @@ from promptflow import tool + @tool def covert_chat_history_to_conversation(chat_history: list) -> dict: conversation = "" diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml index e90434a2d32..97dd7266495 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml @@ -1,3 +1,4 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json id: evaluation flow for multi turn name: evaluation flow for multi turn inputs: diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py index bd766053eea..fce1158e659 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py @@ -1,5 +1,4 @@ -import re -from typing import Mapping, List, Union +from typing import Union from statistics import mean from promptflow import tool from promptflow.tools.aoai import chat as aoai_chat @@ -7,37 +6,39 @@ from promptflow.connections import AzureOpenAIConnection, OpenAIConnection - @tool -def grounding(connection: Union[AzureOpenAIConnection, OpenAIConnection], chat_history: list, prompt: str, model_or_deployment_name: str = "") -> str: - score = [] - for item in chat_history: - prompt_with_context = prompt.replace("{context}", "{{context}}") - prompt_with_all = prompt_with_context.replace("{answer}", "{{answer}}") - if isinstance(connection, AzureOpenAIConnection): - try: - response = aoai_chat( - connection=connection, - prompt=prompt_with_all, - deployment_name=model_or_deployment_name, - context=item["outputs"]["context"], - answer=item["outputs"]["answer"]) - print(response) - score.append(int(response)) - except Exception as e: - if "The API deployment for this resource does not exist" in str(e): - raise Exception( - "Please fill in the deployment name of your Azure OpenAI resource gpt-4 model.") +def grounding(connection: Union[AzureOpenAIConnection, OpenAIConnection], + chat_history: list, + prompt: str, + model_or_deployment_name: str = "") -> str: + score = [] + for item in chat_history: + prompt_with_context = prompt.replace("{context}", "{{context}}") + prompt_with_all = prompt_with_context.replace("{answer}", "{{answer}}") + if isinstance(connection, AzureOpenAIConnection): + try: + response = aoai_chat( + connection=connection, + prompt=prompt_with_all, + deployment_name=model_or_deployment_name, + context=item["outputs"]["context"], + answer=item["outputs"]["answer"]) + print(response) + score.append(int(response)) + except Exception as e: + if "The API deployment for this resource does not exist" in str(e): + raise Exception( + "Please fill in the deployment name of your Azure OpenAI resource gpt-4 model.") - elif isinstance(connection, OpenAIConnection): - response = openai_chat( - connection=connection, - prompt=prompt_with_all, - model=model_or_deployment_name, - context=item["outputs"]["context"], - answer=item["outputs"]["answer"]) - score.append(int(response)) - else: - raise ValueError("Connection must be an instance of AzureOpenAIConnection or OpenAIConnection") - print(score) - return mean(score) \ No newline at end of file + elif isinstance(connection, OpenAIConnection): + response = openai_chat( + connection=connection, + prompt=prompt_with_all, + model=model_or_deployment_name, + context=item["outputs"]["context"], + answer=item["outputs"]["answer"]) + score.append(int(response)) + else: + raise ValueError("Connection must be an instance of AzureOpenAIConnection or OpenAIConnection") + print(score) + return mean(score) diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 index d7aa4e98602..f47114835d3 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 @@ -3,7 +3,7 @@ You are an AI assistant. You will be given the definition of an evaluation metri user: You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: 1. 5: The ANSWER follows logically from the information contained in the CONTEXT. -2. 4: MANSWER follows logically from the information contained in the CONTEXT. +2. 4: Most of the ANSWER follows logically from the information contained in the CONTEXT. 3. 3: The ANSWER follows logically from the information contained in the CONTEXT. 4. 2: The ANSWER follows logically from the information contained in the CONTEXT. 5. 1: The ANSWER is logically false from the information contained in the CONTEXT. diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py index eb7be9be2ce..2c23aab3571 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py @@ -6,7 +6,7 @@ # Please update the function name/signature per need @tool def select_metrics(metrics: str) -> dict: - supported_metrics = ('answer_relevancy','answer_quality','creativity','grounding') + supported_metrics = ('answer_relevancy', 'answer_quality', 'creativity', 'grounding') user_selected_metrics = [metric.strip() for metric in metrics.split(',') if metric] metric_selection_dict = {} for metric in supported_metrics: diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py index 311e96fb619..5cce14db015 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py @@ -1,9 +1,11 @@ from promptflow import tool + # Validate the metric's inputs. def is_valid(metric): return True + @tool def validate_input(chat_history: list, selected_metrics: dict) -> dict: dict_metric_required_fields = {"answer_relevancy": set(["question", "answer"]), @@ -14,7 +16,7 @@ def validate_input(chat_history: list, selected_metrics: dict) -> dict: for item in chat_history: actual_input_cols.update(set(item["inputs"].keys())) actual_input_cols.update(set(item["outputs"].keys())) - break; + break data_validation = selected_metrics for metric in selected_metrics: @@ -25,4 +27,4 @@ def validate_input(chat_history: list, selected_metrics: dict) -> dict: else: print("this path") data_validation[metric] = False - return data_validation \ No newline at end of file + return data_validation diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 index c72b553e072..3bfd064cc8c 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 +++ b/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 @@ -31,7 +31,7 @@ Example Output: } Example Input: -answer: I don't know about the groundbreaking feature of the smartphone invented in 2023 as am unware of information beyond 2022. +answer: I don't know about the groundbreaking feature of the smartphone invented in 2023 as am unaware of information beyond 2022. context: In 2023, a groundbreaking invention was announced: a smartphone with a battery life of one month, revolutionizing the way people use mobile technology. Example Output: { diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py index 02725a5f8d0..63e191a8e42 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py @@ -2,6 +2,7 @@ import json import numpy as np + @tool def calculate(statement_result: str, similarity_score: str) -> str: try: @@ -27,7 +28,7 @@ def calculate(statement_result: str, similarity_score: str) -> str: ] score = 5 * tp / (tp + 0.5 * (fp + fn)) - final_score = weights[0] * score + weights[1] * int(similarity_score) + final_score = weights[0] * score + weights[1] * int(similarity_score) print(score) print(similarity_score) @@ -36,4 +37,4 @@ def calculate(statement_result: str, similarity_score: str) -> str: except Exception as e: print("exception in calculate_answer_correctness: " + str(e)) print("statement_result: " + statement_result) - return np.nan \ No newline at end of file + return np.nan diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py index 901dacdbaa7..012bdf90f85 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py @@ -3,25 +3,26 @@ import numpy as np def calculate_similarity(question_embedding: List, generated_question_embedding: List): - embedding1 = np.array(question_embedding) - embedding2 = np.array(generated_question_embedding) - - # Compute the dot product of the two embeddings - dot_product = np.dot(embedding1, embedding2) - - # Compute the L2 norms (i.e., the lengths) of each embedding - norm_embedding1 = np.linalg.norm(embedding1) - norm_embedding2 = np.linalg.norm(embedding2) - - # Compute the cosine similarity - return dot_product / (norm_embedding1 * norm_embedding2) - + embedding1 = np.array(question_embedding) + embedding2 = np.array(generated_question_embedding) + + # Compute the dot product of the two embeddings + dot_product = np.dot(embedding1, embedding2) + + # Compute the L2 norms (i.e., the lengths) of each embedding + norm_embedding1 = np.linalg.norm(embedding1) + norm_embedding2 = np.linalg.norm(embedding2) + + # Compute the cosine similarity + return dot_product / (norm_embedding1 * norm_embedding2) + + @tool def calculate(question_embedding: List, generated_question_embedding: List, noncommittal: bool) -> str: - cosine_sim = calculate_similarity(question_embedding, generated_question_embedding) - print("noncommittal: ") - print(noncommittal) - print(cosine_sim) - score = 5 * cosine_sim * int(not noncommittal) + cosine_sim = calculate_similarity(question_embedding, generated_question_embedding) + print("noncommittal: ") + print(noncommittal) + print(cosine_sim) + score = 5 * cosine_sim * int(not noncommittal) - return score if score >= 1 else 1 \ No newline at end of file + return score if score >= 1 else 1 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py index 16dc9a5ed0d..41ce7ab3208 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py @@ -2,13 +2,14 @@ import json import numpy as np + @tool def calculate(llm_result: str) -> str: try: score = 1 response = json.loads(llm_result) if response: - result= response.get("result", "") + result = response.get("result", "") print(result) if result: response = [ @@ -26,4 +27,4 @@ def calculate(llm_result: str) -> str: except Exception as e: print("exception in calculate_context_recall: " + str(e)) print("llm_result: " + llm_result) - return np.nan \ No newline at end of file + return np.nan diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py index 2532f7f511c..2902e4b2a81 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py @@ -1,24 +1,24 @@ from promptflow import tool -import numpy as np -import re import json + def get_score(result): try: - if result is not None: - # Parse the JSON string - result_dict = json.loads(result) - - # Extract the score value + if result is not None: + # Parse the JSON string + result_dict = json.loads(result) + + # Extract the score value score = result_dict.get('score', None) print("result: ") print(score) - return score - else: - return None - except json.JSONDecodeError: - print("Invalid JSON string.") - return None + return score + else: + return None + except json.JSONDecodeError: + print("Invalid JSON string.") + return None + @tool def concat_results(answer_relevancy: str = None, @@ -29,14 +29,14 @@ def concat_results(answer_relevancy: str = None, context_precision: str = None, answer_similarity: str = None, answer_correctness: str = None): - + results = {'answer_relevancy': answer_relevancy, - 'answer_quality': get_score(answer_quality), - 'creativity': get_score(creativity), - 'grounding': grounding, - 'context_recall': context_recall, - 'context_precision': context_precision, - 'answer_similarity': answer_similarity, - 'answer_correctness': answer_correctness} - + 'answer_quality': get_score(answer_quality), + 'creativity': get_score(creativity), + 'grounding': grounding, + 'context_recall': context_recall, + 'context_precision': context_precision, + 'answer_similarity': answer_similarity, + 'answer_correctness': answer_correctness} + return results diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 index 0a5e6945a27..08169f198f2 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 +++ b/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 @@ -32,16 +32,16 @@ Example Output: } Example Input: -question: who won 2020 icc world cup? -context: Who won the 2022 ICC Men's T20 World Cup? -The 2022 ICC Men's T20 World Cup, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 World Cup title. +question: who won 2020 icc world game? +context: Who won the 2022 ICC Men's T20 world game? +The 2022 ICC Men's T20 world game, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 world game title. ground truth: England Example Output: { "result": [ { - "statement_1":"England won the 2022 ICC Men's T20 World Cup.", - "reason": "From context it is clear that England defeated Pakistan to win the World Cup.", + "statement_1":"England won the 2022 ICC Men's T20 world game.", + "reason": "From context it is clear that England defeated Pakistan to win the world game.", "attributed": "Yes" } ] diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml index 79ae84edffe..07ef906ffbc 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml @@ -1,3 +1,4 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json id: evaluation_flow_for_single_turn name: Evaluation flow for single turn inputs: diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 index 3bd129c8242..2d9a17238c4 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 +++ b/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 @@ -3,7 +3,7 @@ You are an AI assistant. You will be given the definition of an evaluation metri user: You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: 1. 5: The ANSWER follows logically from the information contained in the CONTEXT. -2. 4: MANSWER follows logically from the information contained in the CONTEXT. +2. 4: Most of the ANSWER follows logically from the information contained in the CONTEXT. 3. 3: The ANSWER follows logically from the information contained in the CONTEXT. 4. 2: The ANSWER follows logically from the information contained in the CONTEXT. 5. 1: The ANSWER is logically false from the information contained in the CONTEXT. diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py b/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py index e476140cefe..f94f607346d 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py @@ -1,6 +1,7 @@ from promptflow import tool import json + @tool def handle_generated_question(llm_result: str) -> str: try: @@ -9,4 +10,4 @@ def handle_generated_question(llm_result: str) -> str: except Exception as e: print("exception in handle_generated_question: " + str(e)) print("llm_result: " + llm_result) - return {"question": "", "noncommittal": true} \ No newline at end of file + return {"question": "", "noncommittal": True} diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py index 138e5b04269..92e6d09f58e 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py @@ -3,7 +3,14 @@ @tool def select_metrics(metrics: str) -> str: - supported_metrics = ('grounding','answer_relevancy','answer_quality','context_recall','context_precision','answer_similarity','answer_correctness','creativity') + supported_metrics = ('grounding', + 'answer_relevancy', + 'answer_quality', + 'context_recall', + 'context_precision', + 'answer_similarity', + 'answer_correctness', + 'creativity') user_selected_metrics = [metric.strip() for metric in metrics.split(',') if metric] metric_selection_dict = {} for metric in supported_metrics: diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py index 01d1fb5bfb3..8d2d982b4e2 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py @@ -28,5 +28,5 @@ def validate_input(question: str, answer: str, context: str, ground_truth: str, if data_validation['answer_correctness']: data_validation['answer_similarity'] = True - + return data_validation diff --git a/examples/flows/standard/simulation-flow/If_continue.py b/examples/flows/standard/simulation-flow/If_continue.py index 60c672b1dc8..8be490c40bc 100644 --- a/examples/flows/standard/simulation-flow/If_continue.py +++ b/examples/flows/standard/simulation-flow/If_continue.py @@ -6,4 +6,4 @@ def if_continue(stop_or_continue: str) -> bool: if "continue" in stop_or_continue.lower(): return True else: - return False \ No newline at end of file + return False diff --git a/examples/flows/standard/simulation-flow/call_llm_chat.py b/examples/flows/standard/simulation-flow/call_llm_chat.py index 145c8a66dd5..d6bdc1de456 100644 --- a/examples/flows/standard/simulation-flow/call_llm_chat.py +++ b/examples/flows/standard/simulation-flow/call_llm_chat.py @@ -1,16 +1,17 @@ from promptflow import tool -import re -from typing import Mapping, List, Union +from typing import Union from promptflow.connections import AzureOpenAIConnection, OpenAIConnection from openai import AzureOpenAI as AzureOpenAIClient +from openai import OpenAI as OpenAIClient from promptflow.tools.common import parse_chat + def parse_questions(completion: str) -> list: questions = [] for item in completion.choices: response = getattr(item.message, "content", "") - print (response) + print(response) questions.append(response) return questions @@ -39,18 +40,17 @@ def call_llm_chat( } if isinstance(connection, AzureOpenAIConnection): client = AzureOpenAIClient(api_key=connection.api_key, - api_version=connection.api_version, - azure_endpoint=connection.api_base) + api_version=connection.api_version, + azure_endpoint=connection.api_base) elif isinstance(connection, OpenAIConnection): client = OpenAIClient(api_key=connection.api_key, - organization=connection.organization, - base_url=connection.base_url) + organization=connection.organization, + base_url=connection.base_url) else: raise ValueError("Unsupported connection type") - completion = client.chat.completions.create(**params) print(completion) questions = parse_questions(completion) - return "\n".join(questions) \ No newline at end of file + return "\n".join(questions) diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/simulation-flow/flow.dag.yaml index 48ad1af53f7..1c8d138a43f 100644 --- a/examples/flows/standard/simulation-flow/flow.dag.yaml +++ b/examples/flows/standard/simulation-flow/flow.dag.yaml @@ -1,3 +1,4 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json id: simulation_standard_flow name: Simulation Standard Flow inputs: From febacacc016096e7e901bf1444b2015f8f96624d Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Mon, 18 Mar 2024 11:26:12 +0800 Subject: [PATCH 069/112] Fix flake8 and flow schema validation errors --- .../flows/evaluation/eval-flow-for-multi-turn/concat_scores.py | 2 +- .../flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml | 2 -- .../eval-flow-for-single-turn/calculate_answer_relevancy.py | 3 ++- .../flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml | 2 -- examples/flows/standard/simulation-flow/flow.dag.yaml | 2 -- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py index 0cf72021005..8f6d722ca09 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py @@ -15,7 +15,7 @@ def get_score(result): return score else: return None - except json.JSONDecodeError: + except json.JSONDecodeError: print("Invalid JSON string.") return None diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml index 97dd7266495..efdacc3cc86 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml @@ -1,6 +1,4 @@ $schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json -id: evaluation flow for multi turn -name: evaluation flow for multi turn inputs: chat_history: type: list diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py index 012bdf90f85..dcdc9e6c529 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py @@ -2,6 +2,7 @@ from typing import List import numpy as np + def calculate_similarity(question_embedding: List, generated_question_embedding: List): embedding1 = np.array(question_embedding) embedding2 = np.array(generated_question_embedding) @@ -9,7 +10,7 @@ def calculate_similarity(question_embedding: List, generated_question_embedding: # Compute the dot product of the two embeddings dot_product = np.dot(embedding1, embedding2) - # Compute the L2 norms (i.e., the lengths) of each embedding + # Compute the L2 norms (i.e., the lengths) of each embedding norm_embedding1 = np.linalg.norm(embedding1) norm_embedding2 = np.linalg.norm(embedding2) diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml index 07ef906ffbc..8f0b5e6dd23 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml @@ -1,6 +1,4 @@ $schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json -id: evaluation_flow_for_single_turn -name: Evaluation flow for single turn inputs: question: type: string diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/simulation-flow/flow.dag.yaml index 1c8d138a43f..7de36f3df87 100644 --- a/examples/flows/standard/simulation-flow/flow.dag.yaml +++ b/examples/flows/standard/simulation-flow/flow.dag.yaml @@ -1,6 +1,4 @@ $schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json -id: simulation_standard_flow -name: Simulation Standard Flow inputs: chat_history: type: list From 29ca97afe7b72c4c67e6bda0e95fbe04af3c63dd Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Wed, 20 Mar 2024 17:32:23 +0800 Subject: [PATCH 070/112] Refine metrics name --- .../eval-flow-for-multi-turn/README.md | 10 +++---- ...levancy.jinja2 => answer_relevance.jinja2} | 4 +-- .../eval-flow-for-multi-turn/concat_scores.py | 8 +++--- ...> convert_chat_history_to_conversation.py} | 2 +- .../eval-flow-for-multi-turn/flow.dag.yaml | 28 +++++++++---------- .../select_metrics.py | 2 +- .../validate_input.py | 4 +-- .../eval-flow-for-single-turn/README.md | 6 ++-- ...levancy.jinja2 => answer_relevance.jinja2} | 0 ...vancy.py => calculate_answer_relevance.py} | 0 .../concat_scores.py | 4 +-- .../eval-flow-for-single-turn/flow.dag.yaml | 28 +++++++++---------- .../select_metrics.py | 2 +- .../validate_input.py | 2 +- .../standard/simulation-flow/flow.dag.yaml | 4 +-- 15 files changed, 52 insertions(+), 52 deletions(-) rename examples/flows/evaluation/eval-flow-for-multi-turn/{answer_relevancy.jinja2 => answer_relevance.jinja2} (95%) rename examples/flows/evaluation/eval-flow-for-multi-turn/{covert_chat_history_to_conversation.py => convert_chat_history_to_conversation.py} (79%) rename examples/flows/evaluation/eval-flow-for-single-turn/{answer_relevancy.jinja2 => answer_relevance.jinja2} (100%) rename examples/flows/evaluation/eval-flow-for-single-turn/{calculate_answer_relevancy.py => calculate_answer_relevance.py} (100%) diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/README.md b/examples/flows/evaluation/eval-flow-for-multi-turn/README.md index 5900b26e53e..03a7feee55e 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/README.md +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/README.md @@ -10,11 +10,11 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_relevancy: Measure whether the answer is relevancy to the question based on provided question, context and answer. +* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. -answer_relevancy is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_quality: Measures the answer quality for each of the following factors based on provided question and answer: +* conversation_quality: Measures the answer quality for each of the following factors based on provided question and answer: - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? @@ -24,7 +24,7 @@ answer_relevancy is scored on a scale of 1 to 5, with 1 being the worst and 5 be - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". -answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +conversation_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. * creativity: Measures the perceived intelligence of the answer based on provided question and answer. Perceived intelligence definition: @@ -39,7 +39,7 @@ creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being th ## Prerequisites -- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, answer_relevancy. +- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: conversation_quality, creativity, answer_relevance. ## Tools used in this flow - LLM tool diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 b/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevance.jinja2 similarity index 95% rename from examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 rename to examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevance.jinja2 index b489ea9c704..0f86e7ff7ab 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevancy.jinja2 +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevance.jinja2 @@ -1,9 +1,9 @@ system: -You are an AI assistant. You will be given the definition of an evaluation metric for assessing the relevancy of bot responses in a conversation to user questions. Your job is to compute an accurate evaluation score using the provided evaluation metric. +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the relevance of bot responses in a conversation to user questions. Your job is to compute an accurate evaluation score using the provided evaluation metric. Relevance measures how well the bot responses addresses the main aspects of the user questions. Consider whether all and only the important aspects are contained in the bot responses when evaluating relevance, score the relevance of the bot responses on a scale of 1 (completely lacks relevance) to 5 (perfect relevance) -- If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the relevancy quality of the conversation and the rating a score for it, and provide some suggestions for how the bot could handle it better. +- If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the relevance quality of the conversation and the rating a score for it, and provide some suggestions for how the bot could handle it better. Tips: - You should read user's question more carefully and try to understand what they are looking for and why. diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py index 8f6d722ca09..e6a28c8858b 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py @@ -21,12 +21,12 @@ def get_score(result): @tool -def concat_results(answer_relevancy: str = None, - answer_quality: str = None, +def concat_results(answer_relevance: str = None, + conversation_quality: str = None, creativity: str = None, grounding: str = None): - results = {'answer_relevancy': get_score(answer_relevancy), - 'answer_quality': get_score(answer_quality), + results = {'answer_relevance': get_score(answer_relevance), + 'conversation_quality': get_score(conversation_quality), 'creativity': get_score(creativity), 'grounding': grounding} diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py b/examples/flows/evaluation/eval-flow-for-multi-turn/convert_chat_history_to_conversation.py similarity index 79% rename from examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py rename to examples/flows/evaluation/eval-flow-for-multi-turn/convert_chat_history_to_conversation.py index c4614e4f6aa..acd3fc359d3 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/covert_chat_history_to_conversation.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/convert_chat_history_to_conversation.py @@ -2,7 +2,7 @@ @tool -def covert_chat_history_to_conversation(chat_history: list) -> dict: +def convert_chat_history_to_conversation(chat_history: list) -> dict: conversation = "" for i in chat_history: conversation += f"User: {i['inputs']['question']}\nBot: {i['outputs']['answer']}\n" diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml index efdacc3cc86..eb55d2fcbda 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml @@ -50,18 +50,18 @@ inputs: is_chat_input: false metrics: type: string - default: creativity,answer_quality,answer_relevancy,grounding + default: creativity,conversation_quality,answer_relevance,grounding is_chat_input: false outputs: creativity: type: string reference: ${concat_scores.output.creativity} - answer_relevancy: + answer_relevance: type: string - reference: ${concat_scores.output.answer_relevancy} - answer_quality: + reference: ${concat_scores.output.answer_relevance} + conversation_quality: type: string - reference: ${concat_scores.output.answer_quality} + reference: ${concat_scores.output.conversation_quality} grounding: type: string reference: ${concat_scores.output.grounding} @@ -83,19 +83,19 @@ nodes: chat_history: ${inputs.chat_history} selected_metrics: ${select_metrics.output} use_variants: false -- name: covert_chat_history_to_conversation +- name: convert_chat_history_to_conversation type: python source: type: code - path: covert_chat_history_to_conversation.py + path: convert_chat_history_to_conversation.py inputs: chat_history: ${inputs.chat_history} use_variants: false -- name: answer_relevancy +- name: answer_relevance type: llm source: type: code - path: answer_relevancy.jinja2 + path: answer_relevance.jinja2 inputs: deployment_name: '' temperature: 0 @@ -108,10 +108,10 @@ nodes: api: chat module: promptflow.tools.aoai activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false -- name: answer_quality +- name: conversation_quality type: llm source: type: code @@ -128,7 +128,7 @@ nodes: api: chat module: promptflow.tools.aoai activate: - when: ${validate_input.output.answer_quality} + when: ${validate_input.output.conversation_quality} is: true use_variants: false - name: creativity @@ -181,8 +181,8 @@ nodes: type: code path: concat_scores.py inputs: - answer_quality: ${answer_quality.output} - answer_relevancy: ${answer_relevancy.output} + conversation_quality: ${conversation_quality.output} + answer_relevance: ${answer_relevance.output} creativity: ${creativity.output} grounding: ${grounding.output} use_variants: false diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py index 2c23aab3571..b81e2adab0e 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py @@ -6,7 +6,7 @@ # Please update the function name/signature per need @tool def select_metrics(metrics: str) -> dict: - supported_metrics = ('answer_relevancy', 'answer_quality', 'creativity', 'grounding') + supported_metrics = ('answer_relevance', 'conversation_quality', 'creativity', 'grounding') user_selected_metrics = [metric.strip() for metric in metrics.split(',') if metric] metric_selection_dict = {} for metric in supported_metrics: diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py index 5cce14db015..c448dd7e0df 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py @@ -8,8 +8,8 @@ def is_valid(metric): @tool def validate_input(chat_history: list, selected_metrics: dict) -> dict: - dict_metric_required_fields = {"answer_relevancy": set(["question", "answer"]), - "answer_quality": set(["question", "answer"]), + dict_metric_required_fields = {"answer_relevance": set(["question", "answer"]), + "conversation_quality": set(["question", "answer"]), "creativity": set(["question", "answer"]), "grounding": set(["answer", "context"])} actual_input_cols = set() diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/README.md b/examples/flows/evaluation/eval-flow-for-single-turn/README.md index 8724e9217a7..5ea79ef179a 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/README.md +++ b/examples/flows/evaluation/eval-flow-for-single-turn/README.md @@ -11,9 +11,9 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_relevancy: Measure whether the answer is relevancy to the question based on provided question, context and answer. +* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. -answer_relevancy is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. * context_recall: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. @@ -56,7 +56,7 @@ creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being th ## Prerequisites -- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, context_recall, context_precision, answer_relevancy, answer_correctness. +- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, context_recall, context_precision, answer_relevance, answer_correctness. ## Tools used in this flow - LLM tool diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 b/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevance.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/answer_relevancy.jinja2 rename to examples/flows/evaluation/eval-flow-for-single-turn/answer_relevance.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py b/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevance.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevancy.py rename to examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevance.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py index 2902e4b2a81..3fee3d279fa 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py @@ -21,7 +21,7 @@ def get_score(result): @tool -def concat_results(answer_relevancy: str = None, +def concat_results(answer_relevance: str = None, answer_quality: str = None, creativity: str = None, grounding: str = None, @@ -30,7 +30,7 @@ def concat_results(answer_relevancy: str = None, answer_similarity: str = None, answer_correctness: str = None): - results = {'answer_relevancy': answer_relevancy, + results = {'answer_relevance': answer_relevance, 'answer_quality': get_score(answer_quality), 'creativity': get_score(creativity), 'grounding': grounding, diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml index 8f0b5e6dd23..7655ed31c47 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml @@ -19,7 +19,7 @@ inputs: is_chat_input: false metrics: type: string - default: grounding,answer_relevancy,answer_quality,context_precision,answer_similarity,creativity,context_recall,answer_correctness + default: grounding,answer_relevance,answer_quality,context_precision,answer_similarity,creativity,context_recall,answer_correctness is_chat_input: false outputs: answer_correctness: @@ -31,9 +31,9 @@ outputs: answer_similarity: type: string reference: ${concat_scores.output.answer_similarity} - answer_relevancy: + answer_relevance: type: string - reference: ${concat_scores.output.answer_relevancy} + reference: ${concat_scores.output.answer_relevance} context_precision: type: string reference: ${concat_scores.output.context_precision} @@ -207,11 +207,11 @@ nodes: when: ${validate_input.output.context_precision} is: true use_variants: false -- name: answer_relevancy +- name: answer_relevance type: llm source: type: code - path: answer_relevancy.jinja2 + path: answer_relevance.jinja2 inputs: deployment_name: '' temperature: 0 @@ -225,7 +225,7 @@ nodes: api: chat module: promptflow.tools.aoai activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false - name: handle_generated_question @@ -234,9 +234,9 @@ nodes: type: code path: handle_generated_question.py inputs: - llm_result: ${answer_relevancy.output} + llm_result: ${answer_relevance.output} activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false - name: embedding_question @@ -249,7 +249,7 @@ nodes: deployment_name: text-embedding-ada-002 input: ${inputs.question} activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false - name: embedding_generated_question @@ -262,20 +262,20 @@ nodes: deployment_name: text-embedding-ada-002 input: ${handle_generated_question.output.question} activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false -- name: calculate_answer_relevancy +- name: calculate_answer_relevance type: python source: type: code - path: calculate_answer_relevancy.py + path: calculate_answer_relevance.py inputs: generated_question_embedding: ${embedding_generated_question.output} noncommittal: ${handle_generated_question.output.noncommittal} question_embedding: ${embedding_question.output} activate: - when: ${validate_input.output.answer_relevancy} + when: ${validate_input.output.answer_relevance} is: true use_variants: false - name: answer_correctness @@ -320,7 +320,7 @@ nodes: inputs: answer_correctness: ${calculate_answer_correctness.output} answer_quality: ${answer_quality.output} - answer_relevancy: ${calculate_answer_relevancy.output} + answer_relevance: ${calculate_answer_relevance.output} answer_similarity: ${answer_similarity.output} context_precision: ${context_precision.output} context_recall: ${calculate_context_recall.output} diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py index 92e6d09f58e..91e37ac6e80 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py @@ -4,7 +4,7 @@ @tool def select_metrics(metrics: str) -> str: supported_metrics = ('grounding', - 'answer_relevancy', + 'answer_relevance', 'answer_quality', 'context_recall', 'context_precision', diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py index 8d2d982b4e2..111db10b617 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py +++ b/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py @@ -5,7 +5,7 @@ def validate_input(question: str, answer: str, context: str, ground_truth: str, selected_metrics: dict) -> dict: input_data = {"question": question, "answer": answer, "context": context, "ground_truth": ground_truth} expected_input_cols = set(input_data.keys()) - dict_metric_required_fields = {"answer_relevancy": set(["question", "answer"]), + dict_metric_required_fields = {"answer_relevance": set(["question", "answer"]), "answer_quality": set(["question", "answer"]), "creativity": set(["question", "answer"]), "grounding": set(["answer", "context"]), diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/simulation-flow/flow.dag.yaml index 7de36f3df87..b9c87273b59 100644 --- a/examples/flows/standard/simulation-flow/flow.dag.yaml +++ b/examples/flows/standard/simulation-flow/flow.dag.yaml @@ -30,11 +30,11 @@ nodes: api: chat module: promptflow.tools.aoai use_variants: false -- name: If_continue +- name: if_continue type: python source: type: code - path: If_continue.py + path: if_continue.py inputs: stop_or_continue: ${verify_if_conversation_stopped.output} use_variants: false From 4237a2dd663588182718c64f19ce7b7cb8817cce Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Wed, 20 Mar 2024 17:55:18 +0800 Subject: [PATCH 071/112] fix name miss match --- .../flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml index eb55d2fcbda..ee6eb61b910 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml +++ b/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml @@ -102,7 +102,7 @@ nodes: top_p: 1 presence_penalty: 0 frequency_penalty: 0 - conversation: ${covert_chat_history_to_conversation.output} + conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI connection: '' api: chat @@ -122,7 +122,7 @@ nodes: top_p: 1 presence_penalty: 0 frequency_penalty: 0 - conversation: ${covert_chat_history_to_conversation.output} + conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI connection: '' api: chat @@ -142,7 +142,7 @@ nodes: top_p: 1 presence_penalty: 0 frequency_penalty: 0 - conversation: ${covert_chat_history_to_conversation.output} + conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI connection: '' api: chat From b5bf3b9e743ad057d5560d1f12c0c0916de0f1dc Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Wed, 20 Mar 2024 18:29:46 +0800 Subject: [PATCH 072/112] Refine --- examples/flows/standard/simulation-flow/flow.dag.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/simulation-flow/flow.dag.yaml index b9c87273b59..0ddf04b36a7 100644 --- a/examples/flows/standard/simulation-flow/flow.dag.yaml +++ b/examples/flows/standard/simulation-flow/flow.dag.yaml @@ -46,7 +46,7 @@ nodes: inputs: chat_history: ${inputs.chat_history} activate: - when: ${If_continue.output} + when: ${if_continue.output} is: true use_variants: false - name: call_llm_chat From 8949c0803c052de285cd273c2a39020d75aca913 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:41:57 +0800 Subject: [PATCH 073/112] Remove copy flow folder, fix cspell and doc link ci (#2253) # Description Remove copying flow folder Test scenarios: - portal - aoai connection and deployment name override exp link: https://ml.azure.com/runs/gray_balloon_k6f21rhwhs?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/providers/Microsoft.MachineLearningServices/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47# - open connection and model override exp link: https://ml.azure.com/runs/ashy_heart_mkkh2jdpxf?wsid=/subscriptions/96aede12-2f73-41cb-b983-6d11a904839b/resourcegroups/promptflow/providers/Microsoft.MachineLearningServices/workspaces/yaopfeus&tid=72f988bf-86f1-41af-91ab-2d7cd011db47 - local: ![image](https://github.com/microsoft/promptflow/assets/46446115/52f45ef4-670b-4082-b179-26577984cca0) --------- Co-authored-by: yalu4 --- .cspell.json | 3 +- .../cloud/azureai/generate-test-data-cloud.md | 14 +- docs/cloud/index.md | 1 + docs/how-to-guides/generate-test-data.md | 24 +-- examples/gen_test_data/config.yml.example | 18 ++- .../gen_test_data/gen_test_data/common.py | 32 ---- .../generate_test_data_flow/flow.dag.yaml | 13 +- .../generate_question.py | 23 ++- .../generate_suggested_answer.py | 20 ++- .../generate_test_data_flow/utils.py | 37 +++-- .../validate_question.py | 18 ++- .../validate_suggested_answer.py | 20 ++- .../validate_text_chunk.py | 18 ++- examples/gen_test_data/gen_test_data/run.py | 148 +++++++++--------- examples/gen_test_data/requirements.txt | 2 +- examples/gen_test_data/requirements_cloud.txt | 2 +- 16 files changed, 217 insertions(+), 176 deletions(-) diff --git a/.cspell.json b/.cspell.json index 91b02115b2a..4a889c0c581 100644 --- a/.cspell.json +++ b/.cspell.json @@ -187,7 +187,8 @@ "pywin", "STARTF", "mltable", - "setenv" + "setenv", + "pypdf" ], "flagWords": [ "Prompt Flow" diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index 0bf66809ef5..a12dc53b96d 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -4,10 +4,10 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Prerequisites -1. Go through [local test data generation guide](../../how-to-guides/generate-test-data.md) and prepare your [test data generation flow](../../../examples/gen_test_data/gen_test_data/generate_test_data_flow/). -2. Go to the [example_gen_test_data](../../../examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. +1. Go through [local test data generation guide](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/docs/how-to-guides/generate-test-data.md) and prepare your [test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/). +2. Go to the [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. 3. Prepare cloud environment. - - Navigate to file [conda.yml](../../../examples/gen_test_data/conda.yml). + - Navigate to file [conda.yml](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/conda.yml). - For specific document file types, you may need to install extra packages: - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` @@ -17,11 +17,11 @@ This guide will help you learn how to generate test data on Azure AI, so that yo 4. Prepare Azure AI resources in cloud. - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). - A compute target - [Learn more about compute cluster](https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2). -5. [Create cloud connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start.html#create-necessary-connections) +5. [Create cloud connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start/index.html#create-necessary-connections) 6. Prepare config.ini - - Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](../../../examples/gen_test_data/config.yml.example). + - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. + - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/config.yml.example). ``` cp config.yml.example config.yml ``` @@ -30,7 +30,7 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in cloud. -- Navigate to [example_gen_test_data](../../../examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run --cloud diff --git a/docs/cloud/index.md b/docs/cloud/index.md index c7ef25b25ad..6a43ab5f6eb 100644 --- a/docs/cloud/index.md +++ b/docs/cloud/index.md @@ -37,4 +37,5 @@ azureai/deploy-to-azure-appservice azureai/use-flow-in-azure-ml-pipeline.md azureai/faq azureai/runtime-change-log.md +azureai/generate-test-data-cloud.md ``` diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index b2ea66a0da7..6f625f053ac 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,7 +18,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](../../examples/gen_test_data) folder and install required packages. +2. Prepare local environment. Go to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder and install required packages. ```bash pip install -r requirements.txt @@ -35,8 +35,8 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 4. [Create connections](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) 5. Prepare config.ini - - Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](../../examples/gen_test_data/config.yml.example). + - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. + - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/config.yml.example). ``` cp config.yml.example config.yml ``` @@ -44,8 +44,8 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene ## Create a test data generation flow - - Open the [sample test data generation flow](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/) in VSCode. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - - Fill in node inputs including `connection`, `model_or_deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/) in VSCode. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. + - Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. @@ -57,17 +57,17 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - - [*generate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - - [*generate suggested answer prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. + - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - [*score text chunk prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (default 4), validation fails. - - [*validate question prompt*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](../../examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (default 4), validation fails. + - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. ## Generate test data -- Navigate to [example_gen_test_data](../../examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash @@ -76,4 +76,4 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. -If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](../cloud/azureai/generate-test-data-cloud.md) for more detailed steps. +If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. diff --git a/examples/gen_test_data/config.yml.example b/examples/gen_test_data/config.yml.example index eb6c944e499..6b1eb42b979 100644 --- a/examples/gen_test_data/config.yml.example +++ b/examples/gen_test_data/config.yml.example @@ -14,19 +14,25 @@ flow_folder: "" node_inputs_override: # Override some node inputs, if not fill in "node_inputs_override", will use the values in flow.dag.yaml validate_text_chunk: # node name in flow.dag.yaml connection: "" # input name of `validate_text_chunk` - model_or_deployment_name: "" + # Use `deployment_name` for Azure OpenAI connection, `model` for OpenAI + deployment_name: "" + # model: "" generate_question: connection: "" - model_or_deployment_name: "" + deployment_name: "" + # model: "" validate_question: connection: "" - model_or_deployment_name: "" + deployment_name: "" + # model: "" generate_suggested_answer: connection: "" - model_or_deployment_name: "" + deployment_name: "" + # model: "" validate_suggested_answer: connection: "" - model_or_deployment_name: "" + deployment_name: "" + # model: "" # Local section: this section is for local test data generation related configuration. Can skip if not run in local. @@ -46,4 +52,4 @@ prs_mini_batch_size: 1 prs_max_concurrency_per_instance: 4 prs_max_retry_count: 3 prs_run_invocation_time: 800 -prs_allowed_failed_count: -1 \ No newline at end of file +prs_allowed_failed_count: -1 diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 8475b3a99a6..60bb5051f89 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -1,6 +1,5 @@ import json import re -import shutil import sys import time import typing as t @@ -9,7 +8,6 @@ from constants import DOCUMENT_NODE, NODES_FILE_NAME, SUPPORT_FILE_TYPE, TEXT_CHUNK from promptflow._utils.logger_utils import get_logger -from promptflow._utils.yaml_utils import dump_yaml, load_yaml def split_document(chunk_size, chunk_overlap, documents_folder, document_node_output): @@ -143,36 +141,6 @@ def print_progress(log_file_path: str, process): progress_bar.close() -def copy_flow_folder_and_set_node_inputs(copied_folder, flow_folder, node_inputs_override): - logger = get_logger("data.gen") - logger.info("Overriding the values of node inputs in flag.dag.yaml...") - if not (Path(flow_folder) / "flow.dag.yaml").is_file(): - raise ValueError(f"The file 'flag.dag.yaml' does not exist in {flow_folder}.") - - if Path(copied_folder).exists(): - shutil.rmtree(copied_folder) - shutil.copytree(flow_folder, copied_folder) - - with open(Path(copied_folder) / "flow.dag.yaml", "r", encoding="utf-8") as f: - data = load_yaml(f) - - if node_inputs_override and len(node_inputs_override) > 0: - # Update the YAML data according to the config dict - for node_name, inputs in node_inputs_override.items(): - node = next((node for node in data["nodes"] if node["name"] == node_name), None) - if node is None: - raise ValueError(f"Node '{node_name}' not found in the flag.dag.yaml.") - for input_name, input_value in inputs.items(): - if input_name not in node["inputs"]: - raise ValueError(f"Input '{input_name}' not found in node '{node_name}'.") - - if not (input_value.startswith("<") and input_value.endswith(">")): - node["inputs"][input_name] = input_value - - with open(Path(copied_folder) / "flow.dag.yaml", "w", encoding="utf-8") as f: - dump_yaml(data, f) - - def convert_to_abs_path(file_path: str) -> str: if not file_path: return file_path diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml index 2ecb428677e..2732d4b1643 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml @@ -5,9 +5,11 @@ inputs: text_chunk: type: string is_chat_input: false - default: Albert Einstein (14 March 1879 - 18 April 1955) was a German-born - theoretical physicist who is widely held to be one of the greatest and - most influential scientists of all time. + default: Prompt flow is a suite of development tools designed to streamline the + end-to-end development cycle of LLM-based AI applications, from ideation, + prototyping, testing, evaluation to production deployment and monitoring. + It makes prompt engineering much easier and enables you to build LLM apps + with production quality. outputs: question: type: string @@ -60,7 +62,6 @@ nodes: path: generate_question.py inputs: connection: "" - model_or_deployment_name: "" context: ${validate_text_chunk.output.context} temperature: 0.2 generate_question_prompt: ${generate_question_prompt.output} @@ -72,7 +73,6 @@ nodes: path: validate_question.py inputs: connection: "" - model_or_deployment_name: "" temperature: 0.2 generated_question: ${generate_question.output} validate_question_prompt: ${validate_question_prompt.output} @@ -87,7 +87,6 @@ nodes: context: ${inputs.text_chunk} generate_suggested_answer_prompt: ${generate_suggested_answer_prompt.output} question: ${validate_question.output.question} - model_or_deployment_name: "" temperature: 0.2 use_variants: false - name: generate_debug_info @@ -114,7 +113,6 @@ nodes: path: validate_suggested_answer.py inputs: connection: "" - model_or_deployment_name: "" suggested_answer: ${generate_suggested_answer.output} validate_suggested_answer_prompt: ${validate_suggested_answer_prompt.output} temperature: 0.2 @@ -128,5 +126,4 @@ nodes: score_text_chunk_prompt: ${score_text_chunk_prompt.output} context: ${inputs.text_chunk} score_threshold: 4 - model_or_deployment_name: "" temperature: 0.2 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py index 6cddc4f6b55..c2d2354cc75 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py @@ -3,28 +3,37 @@ from utils import llm_call from promptflow import tool +from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection -@tool +@tool( + input_settings={ + "deployment_name": InputSetting( + enabled_by="connection", + enabled_by_type=["AzureOpenAIConnection"], + capabilities={"completion": False, "chat_completion": True, "embeddings": False}, + ), + "model": InputSetting(enabled_by="connection", enabled_by_type=["OpenAIConnection"]), + } +) def generate_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, generate_question_prompt: str, + deployment_name: str = "", + model: str = "", context: str = None, - temperature: float = 0.2 + temperature: float = 0.2, ): """ Generates a question based on the given context. Returns: - dict: The generated seed question. + str: The generated seed question. """ # text chunk is not valid, just skip test data gen. if not context: return "" - seed_question = llm_call( - connection, model_or_deployment_name, generate_question_prompt, temperature=temperature - ) + seed_question = llm_call(connection, model, deployment_name, generate_question_prompt, temperature=temperature) return seed_question diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py index ef738d04b9b..be607ba0262 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py @@ -3,17 +3,28 @@ from utils import llm_call from promptflow import tool +from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection -@tool +@tool( + input_settings={ + "deployment_name": InputSetting( + enabled_by="connection", + enabled_by_type=["AzureOpenAIConnection"], + capabilities={"completion": False, "chat_completion": True, "embeddings": False}, + ), + "model": InputSetting(enabled_by="connection", enabled_by_type=["OpenAIConnection"]), + } +) def generate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, question: str, context: str, generate_suggested_answer_prompt: str, - temperature: float = 0.2 + deployment_name: str = "", + model: str = "", + temperature: float = 0.2, ): """ Generates a suggested answer based on the given prompts and context information. @@ -24,7 +35,8 @@ def generate_suggested_answer( if question and context: return llm_call( connection, - model_or_deployment_name, + model, + deployment_name, generate_suggested_answer_prompt, temperature=temperature, ) diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py index f38ace88f24..25f4143ab68 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py @@ -37,7 +37,7 @@ class ErrorMsg: def llm_call( - connection, model_or_deployment_name, prompt, response_format=ResponseFormat.TEXT, temperature=1.0, max_tokens=None + connection, model, deployment_name, prompt, response_format=ResponseFormat.TEXT, temperature=1.0, max_tokens=None ): response_format = "json_object" if response_format.lower() == "json" else response_format # avoid unnecessary jinja2 template re-rendering and potential error. @@ -46,7 +46,7 @@ def llm_call( return aoai_chat( connection=connection, prompt=prompt, - deployment_name=model_or_deployment_name, + deployment_name=deployment_name, temperature=temperature, max_tokens=max_tokens, response_format={"type": response_format}, @@ -55,7 +55,7 @@ def llm_call( return openai_chat( connection=connection, prompt=prompt, - model=model_or_deployment_name, + model=model, temperature=temperature, max_tokens=max_tokens, response_format={"type": response_format}, @@ -72,11 +72,24 @@ def get_question_type(testset_distribution) -> str: def get_suggested_answer_validation_res( - connection, model_or_deployment_name, prompt, suggested_answer: str, temperature: float, - max_tokens: int=None, response_format: ResponseFormat = ResponseFormat.TEXT + connection, + model, + deployment_name, + prompt, + suggested_answer: str, + temperature: float, + max_tokens: int = None, + response_format: ResponseFormat = ResponseFormat.TEXT, ): - rsp = llm_call(connection, model_or_deployment_name, prompt, temperature=temperature, max_tokens=max_tokens, - response_format=response_format) + rsp = llm_call( + connection, + model, + deployment_name, + prompt, + temperature=temperature, + max_tokens=max_tokens, + response_format=response_format, + ) return retrieve_verdict_and_print_reason( rsp=rsp, validate_obj_name=ValidateObj.SUGGESTED_ANSWER, validate_obj=suggested_answer ) @@ -84,27 +97,29 @@ def get_suggested_answer_validation_res( def get_question_validation_res( connection, - model_or_deployment_name, + model, + deployment_name, prompt, question: str, response_format: ResponseFormat, temperature: float, max_tokens: int = None, ): - rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) + rsp = llm_call(connection, model, deployment_name, prompt, response_format, temperature, max_tokens) return retrieve_verdict_and_print_reason(rsp=rsp, validate_obj_name=ValidateObj.QUESTION, validate_obj=question) def get_text_chunk_score( connection, - model_or_deployment_name, + model, + deployment_name, prompt, response_format: ResponseFormat, score_threshold: float, temperature: float, max_tokens: int = None, ): - rsp = llm_call(connection, model_or_deployment_name, prompt, response_format, temperature, max_tokens) + rsp = llm_call(connection, model, deployment_name, prompt, response_format, temperature, max_tokens) data = _load_json_rsp(rsp) score_float = 0 reason = "" diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py index 20fcfd18c35..e86e3ea1a5d 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py @@ -3,15 +3,26 @@ from utils import ErrorMsg, QuestionType, ResponseFormat, get_question_validation_res from promptflow import tool +from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection -@tool +@tool( + input_settings={ + "deployment_name": InputSetting( + enabled_by="connection", + enabled_by_type=["AzureOpenAIConnection"], + capabilities={"completion": False, "chat_completion": True, "embeddings": False}, + ), + "model": InputSetting(enabled_by="connection", enabled_by_type=["OpenAIConnection"]), + } +) def validate_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, generated_question: str, validate_question_prompt: str, + deployment_name: str = "", + model: str = "", response_format: str = ResponseFormat.TEXT, temperature: float = 0.2, ): @@ -28,7 +39,8 @@ def validate_question( validation_res = get_question_validation_res( connection, - model_or_deployment_name, + model, + deployment_name, validate_question_prompt, generated_question, response_format, diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py index 636687957f5..b9c88bf4e03 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py @@ -3,18 +3,27 @@ from utils import ErrorMsg, get_suggested_answer_validation_res from promptflow import tool +from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection -# The inputs section will change based on the arguments of the tool function, after you save the code -# Adding type to arguments and return value will help the system show the types properly -# Please update the function name/signature per need +@tool( + input_settings={ + "deployment_name": InputSetting( + enabled_by="connection", + enabled_by_type=["AzureOpenAIConnection"], + capabilities={"completion": False, "chat_completion": True, "embeddings": False}, + ), + "model": InputSetting(enabled_by="connection", enabled_by_type=["OpenAIConnection"]), + } +) @tool def validate_suggested_answer( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, suggested_answer: str, validate_suggested_answer_prompt: str, + deployment_name: str = "", + model: str = "", temperature: float = 0.2, response_format: str = "text", ): @@ -29,7 +38,8 @@ def validate_suggested_answer( validation_res = get_suggested_answer_validation_res( connection, - model_or_deployment_name, + model, + deployment_name, validate_suggested_answer_prompt, suggested_answer, temperature, diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py index a45b57ec3e6..99ff2f09b8f 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py +++ b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py @@ -3,15 +3,26 @@ from utils import ErrorMsg, ResponseFormat, get_text_chunk_score from promptflow import tool +from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection -@tool +@tool( + input_settings={ + "deployment_name": InputSetting( + enabled_by="connection", + enabled_by_type=["AzureOpenAIConnection"], + capabilities={"completion": False, "chat_completion": True, "embeddings": False}, + ), + "model": InputSetting(enabled_by="connection", enabled_by_type=["OpenAIConnection"]), + } +) def validate_text_chunk( connection: Union[OpenAIConnection, AzureOpenAIConnection], - model_or_deployment_name: str, score_text_chunk_prompt: str, score_threshold: float, + deployment_name: str = "", + model: str = "", context: str = None, response_format: str = ResponseFormat.TEXT, temperature: float = 0.2, @@ -24,7 +35,8 @@ def validate_text_chunk( """ text_chunk_score_res = get_text_chunk_score( connection, - model_or_deployment_name, + model, + deployment_name, score_text_chunk_prompt, response_format, score_threshold, diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 7a728646ce9..280ef20fe90 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -1,7 +1,6 @@ import argparse import json import os -import shutil import time from datetime import datetime from pathlib import Path @@ -17,7 +16,6 @@ from common import ( # noqa: E402 clean_data, convert_to_abs_path, - copy_flow_folder_and_set_node_inputs, count_non_blank_lines, local_path_exists, non_padding_path, @@ -30,20 +28,22 @@ logger = get_logger("data.gen") -def batch_run_flow( - flow_folder: str, - flow_input_data: str, - flow_batch_run_size: int, -): +def batch_run_flow(flow_folder: str, flow_input_data: str, flow_batch_run_size: int, node_inputs_override: dict): logger.info("Step 2: Start to batch run 'generate_test_data_flow'...") import subprocess run_name = f"test_data_gen_{datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}" # TODO: replace the separate process to submit batch run with batch run async method when it's available. + connections_str = "" + for node_name, node_val in node_inputs_override.items(): + for k, v in node_val.items(): + connections_str += f"{node_name}.{k}={v} " + connections_str = connections_str.rstrip() + cmd = ( f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " - f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}' --debug" + f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}' --connections {connections_str} --debug" ) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.info( @@ -87,6 +87,7 @@ def run_local( flow_batch_run_size: int, output_folder: str, should_skip_split: bool, + node_inputs_override: dict, ): text_chunks_path = document_nodes_file output_folder = Path(output_folder) / datetime.now().strftime("%b-%d-%Y-%H-%M-%S") @@ -96,7 +97,7 @@ def run_local( if not should_skip_split: text_chunks_path = split_document(document_chunk_size, document_chunk_overlap, documents_folder, output_folder) - run_name, process = batch_run_flow(flow_folder, text_chunks_path, flow_batch_run_size) + run_name, process = batch_run_flow(flow_folder, text_chunks_path, flow_batch_run_size, node_inputs_override) run_folder_path = Path.home() / f".promptflow/.runs/{run_name}" print_progress(run_folder_path / "logs.txt", process) @@ -140,6 +141,7 @@ def run_cloud( prs_run_invocation_time: int, prs_allowed_failed_count: int, should_skip_split: bool, + node_inputs_override: dict, ): # lazy import azure dependencies try: @@ -188,7 +190,7 @@ def gen_test_data_pipeline( ).outputs.document_node_output ) flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_flow"}])( - data=data, text_chunk="${data.text_chunk}" + data=data, text_chunk="${data.text_chunk}", connections=node_inputs_override ) flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance @@ -254,68 +256,64 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str + "Please check if you are under the wrong directory or the file is missing." ) - copied_flow_folder = config["flow_folder"] + "_" + time.strftime("%b-%d-%Y-%H-%M-%S") + "_temp" - try: - should_skip_split_documents = False - document_nodes_file = convert_to_abs_path(config.get("document_nodes_file", None)) - documents_folder = convert_to_abs_path(config.get("documents_folder", None)) - flow_folder = convert_to_abs_path(config.get("flow_folder", None)) - output_folder = convert_to_abs_path(config.get("output_folder", None)) - validate_path_func = non_padding_path if args.cloud else local_path_exists - - if document_nodes_file and validate_path_func(document_nodes_file): - should_skip_split_documents = True - elif not documents_folder or not validate_path_func(documents_folder): - raise Exception( - "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" - f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" - ) - - if args.cloud: - logger.info("Start to generate test data at cloud...") - else: - logger.info("Start to generate test data at local...") - - if should_skip_split_documents: - logger.info( - "Skip step 1 'Split documents to document nodes' as received document nodes from " - f"input file path '{document_nodes_file}'." - ) - if Path(document_nodes_file).is_file(): - logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") - - copy_flow_folder_and_set_node_inputs(copied_flow_folder, flow_folder, config.get("node_inputs_override", None)) - - if args.cloud: - run_cloud( - documents_folder, - config.get("document_chunk_size", 512), - config.get("document_chunk_overlap", 100), - document_nodes_file, - copied_flow_folder, - config["subscription_id"], - config["resource_group"], - config["workspace_name"], - config["aml_cluster"], - config.get("prs_instance_count", 2), - config.get("prs_mini_batch_size", 1), - config.get("prs_max_concurrency_per_instance", 4), - config.get("prs_max_retry_count", 3), - config.get("prs_run_invocation_time", 800), - config.get("prs_allowed_failed_count", -1), - should_skip_split_documents, - ) - else: - run_local( - documents_folder, - config.get("document_chunk_size", 512), - config.get("document_chunk_overlap", 100), - document_nodes_file, - copied_flow_folder, - config.get("flow_batch_run_size", 16), - output_folder, - should_skip_split_documents, - ) - finally: - if os.path.exists(copied_flow_folder): - shutil.rmtree(copied_flow_folder) + should_skip_split_documents = False + document_nodes_file = convert_to_abs_path(config.get("document_nodes_file", None)) + documents_folder = convert_to_abs_path(config.get("documents_folder", None)) + flow_folder = convert_to_abs_path(config.get("flow_folder", None)) + output_folder = convert_to_abs_path(config.get("output_folder", None)) + validate_path_func = non_padding_path if args.cloud else local_path_exists + node_inputs_override = config.get("node_inputs_override", None) + + if document_nodes_file and validate_path_func(document_nodes_file): + should_skip_split_documents = True + elif not documents_folder or not validate_path_func(documents_folder): + raise Exception( + "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" + f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" + ) + + if args.cloud: + logger.info("Start to generate test data at cloud...") + else: + logger.info("Start to generate test data at local...") + + if should_skip_split_documents: + logger.info( + "Skip step 1 'Split documents to document nodes' as received document nodes from " + f"input file path '{document_nodes_file}'." + ) + if Path(document_nodes_file).is_file(): + logger.info(f"Collected {count_non_blank_lines(document_nodes_file)} document nodes.") + + if args.cloud: + run_cloud( + documents_folder, + config.get("document_chunk_size", 512), + config.get("document_chunk_overlap", 100), + document_nodes_file, + flow_folder, + config["subscription_id"], + config["resource_group"], + config["workspace_name"], + config["aml_cluster"], + config.get("prs_instance_count", 2), + config.get("prs_mini_batch_size", 1), + config.get("prs_max_concurrency_per_instance", 4), + config.get("prs_max_retry_count", 3), + config.get("prs_run_invocation_time", 800), + config.get("prs_allowed_failed_count", -1), + should_skip_split_documents, + node_inputs_override, + ) + else: + run_local( + documents_folder, + config.get("document_chunk_size", 512), + config.get("document_chunk_overlap", 100), + document_nodes_file, + flow_folder, + config.get("flow_batch_run_size", 16), + output_folder, + should_skip_split_documents, + node_inputs_override, + ) diff --git a/examples/gen_test_data/requirements.txt b/examples/gen_test_data/requirements.txt index 3e1dedd5778..2b62527850f 100644 --- a/examples/gen_test_data/requirements.txt +++ b/examples/gen_test_data/requirements.txt @@ -1,3 +1,3 @@ -promptflow>=1.4.0 +promptflow>=1.7.0 promptflow-tools llama_index diff --git a/examples/gen_test_data/requirements_cloud.txt b/examples/gen_test_data/requirements_cloud.txt index e055a61e61a..e34a3c6d033 100644 --- a/examples/gen_test_data/requirements_cloud.txt +++ b/examples/gen_test_data/requirements_cloud.txt @@ -1,4 +1,4 @@ -promptflow>=1.4.0 +promptflow>=1.7.0 promptflow-tools azure-ai-ml mldesigner From 77b885eaa169e4d9507e0b398450d1fd5e0431c2 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Wed, 27 Mar 2024 14:52:49 +0800 Subject: [PATCH 074/112] change file name --- .../standard/simulation-flow/{If_continue.py => if_continue.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/flows/standard/simulation-flow/{If_continue.py => if_continue.py} (100%) diff --git a/examples/flows/standard/simulation-flow/If_continue.py b/examples/flows/standard/simulation-flow/if_continue.py similarity index 100% rename from examples/flows/standard/simulation-flow/If_continue.py rename to examples/flows/standard/simulation-flow/if_continue.py From 1d2a9dab2e035b752c690d088ab550fdf5854373 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 10:16:13 +0800 Subject: [PATCH 075/112] Change flow name --- .../README.md | 2 +- .../aggregate_results.py | 0 .../answer_relevance.jinja2 | 0 .../concat_scores.py | 0 .../conversation_quality_prompt.jinja2 | 0 .../convert_chat_history_to_conversation.py | 0 .../creativity.jinja2 | 0 .../flow.dag.yaml | 0 .../grounding.py | 0 .../grounding_prompt.jinja2 | 0 .../requirements.txt | 0 .../select_metrics.py | 0 .../validate_input.py | 0 .../README.md | 2 +- .../aggregate.py | 0 .../answer_correctness.jinja2 | 0 .../answer_quality.jinja2 | 0 .../answer_relevance.jinja2 | 0 .../answer_similarity.jinja2 | 0 .../calculate_answer_correctness.py | 0 .../calculate_answer_relevance.py | 0 .../calculate_context_recall.py | 0 .../concat_scores.py | 0 .../context_precision.jinja2 | 0 .../context_recall.jinja2 | 0 .../creativity.jinja2 | 0 .../flow.dag.yaml | 0 .../flow.meta.yaml | 0 .../grounding.jinja2 | 0 .../handle_generated_question.py | 0 .../requirements.txt | 0 .../samples.json | 0 .../select_metrics.py | 0 .../validate_input.py | 0 .../{simulation-flow => question-simulation}/README.md | 4 ++-- .../{simulation-flow => question-simulation}/call_llm_chat.py | 0 .../{simulation-flow => question-simulation}/flow.dag.yaml | 0 .../{simulation-flow => question-simulation}/flow_output.py | 0 .../human_prompt.jinja2 | 0 .../{simulation-flow => question-simulation}/if_continue.py | 0 .../{simulation-flow => question-simulation}/requirements.txt | 0 .../verify_if_conversation_stopped.jinja2 | 0 42 files changed, 4 insertions(+), 4 deletions(-) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/README.md (99%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/aggregate_results.py (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/answer_relevance.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/concat_scores.py (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/conversation_quality_prompt.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/convert_chat_history_to_conversation.py (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/creativity.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/flow.dag.yaml (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/grounding.py (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/grounding_prompt.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/requirements.txt (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/select_metrics.py (100%) rename examples/flows/evaluation/{eval-flow-for-multi-turn => eval-multi-turn-metrics}/validate_input.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/README.md (99%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/aggregate.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/answer_correctness.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/answer_quality.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/answer_relevance.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/answer_similarity.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/calculate_answer_correctness.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/calculate_answer_relevance.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/calculate_context_recall.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/concat_scores.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/context_precision.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/context_recall.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/creativity.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/flow.dag.yaml (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/flow.meta.yaml (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/grounding.jinja2 (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/handle_generated_question.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/requirements.txt (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/samples.json (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/select_metrics.py (100%) rename examples/flows/evaluation/{eval-flow-for-single-turn => eval-single-turn-metrics}/validate_input.py (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/README.md (86%) rename examples/flows/standard/{simulation-flow => question-simulation}/call_llm_chat.py (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/flow.dag.yaml (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/flow_output.py (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/human_prompt.jinja2 (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/if_continue.py (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/requirements.txt (100%) rename examples/flows/standard/{simulation-flow => question-simulation}/verify_if_conversation_stopped.jinja2 (100%) diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/README.md b/examples/flows/evaluation/eval-multi-turn-metrics/README.md similarity index 99% rename from examples/flows/evaluation/eval-flow-for-multi-turn/README.md rename to examples/flows/evaluation/eval-multi-turn-metrics/README.md index 03a7feee55e..ff91f2320d4 100644 --- a/examples/flows/evaluation/eval-flow-for-multi-turn/README.md +++ b/examples/flows/evaluation/eval-multi-turn-metrics/README.md @@ -1,4 +1,4 @@ -# Evaluation flow for single turn: +# Evaluation multi turn metrics: This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py b/examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/aggregate_results.py rename to examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevance.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/answer_relevance.jinja2 rename to examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py b/examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/concat_scores.py rename to examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/conversation_quality_prompt.jinja2 rename to examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/convert_chat_history_to_conversation.py b/examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/convert_chat_history_to_conversation.py rename to examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/creativity.jinja2 rename to examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml b/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/flow.dag.yaml rename to examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py b/examples/flows/evaluation/eval-multi-turn-metrics/grounding.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/grounding.py rename to examples/flows/evaluation/eval-multi-turn-metrics/grounding.py diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/grounding_prompt.jinja2 rename to examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt b/examples/flows/evaluation/eval-multi-turn-metrics/requirements.txt similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/requirements.txt rename to examples/flows/evaluation/eval-multi-turn-metrics/requirements.txt diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py b/examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/select_metrics.py rename to examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py diff --git a/examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py b/examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-multi-turn/validate_input.py rename to examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/README.md b/examples/flows/evaluation/eval-single-turn-metrics/README.md similarity index 99% rename from examples/flows/evaluation/eval-flow-for-single-turn/README.md rename to examples/flows/evaluation/eval-single-turn-metrics/README.md index 5ea79ef179a..6c1a1380ba8 100644 --- a/examples/flows/evaluation/eval-flow-for-single-turn/README.md +++ b/examples/flows/evaluation/eval-single-turn-metrics/README.md @@ -1,4 +1,4 @@ -# Evaluation flow for single turn: +# Evaluation single turn metrics: This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py b/examples/flows/evaluation/eval-single-turn-metrics/aggregate.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/aggregate.py rename to examples/flows/evaluation/eval-single-turn-metrics/aggregate.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/answer_correctness.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/answer_quality.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_relevance.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/answer_relevance.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/answer_similarity.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_correctness.py rename to examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevance.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/calculate_answer_relevance.py rename to examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/calculate_context_recall.py rename to examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py b/examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/concat_scores.py rename to examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/context_precision.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/context_recall.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/creativity.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml b/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/flow.dag.yaml rename to examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml b/examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/flow.meta.yaml rename to examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/grounding.jinja2 rename to examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py b/examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/handle_generated_question.py rename to examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt b/examples/flows/evaluation/eval-single-turn-metrics/requirements.txt similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/requirements.txt rename to examples/flows/evaluation/eval-single-turn-metrics/requirements.txt diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/samples.json b/examples/flows/evaluation/eval-single-turn-metrics/samples.json similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/samples.json rename to examples/flows/evaluation/eval-single-turn-metrics/samples.json diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py b/examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/select_metrics.py rename to examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py diff --git a/examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py b/examples/flows/evaluation/eval-single-turn-metrics/validate_input.py similarity index 100% rename from examples/flows/evaluation/eval-flow-for-single-turn/validate_input.py rename to examples/flows/evaluation/eval-single-turn-metrics/validate_input.py diff --git a/examples/flows/standard/simulation-flow/README.md b/examples/flows/standard/question-simulation/README.md similarity index 86% rename from examples/flows/standard/simulation-flow/README.md rename to examples/flows/standard/question-simulation/README.md index 4c1de1cff04..e8d24aec41e 100644 --- a/examples/flows/standard/simulation-flow/README.md +++ b/examples/flows/standard/question-simulation/README.md @@ -1,6 +1,6 @@ -# Simulation flow: +# Question simulation: -This simulation flow is used to generate suggestions for the next question based on the previous chat history. +This question simulation flow is used to generate suggestions for the next question based on the previous chat history. ## Flow inputs * chat_history (list): the previous chat_history, the format for it is as follows: diff --git a/examples/flows/standard/simulation-flow/call_llm_chat.py b/examples/flows/standard/question-simulation/call_llm_chat.py similarity index 100% rename from examples/flows/standard/simulation-flow/call_llm_chat.py rename to examples/flows/standard/question-simulation/call_llm_chat.py diff --git a/examples/flows/standard/simulation-flow/flow.dag.yaml b/examples/flows/standard/question-simulation/flow.dag.yaml similarity index 100% rename from examples/flows/standard/simulation-flow/flow.dag.yaml rename to examples/flows/standard/question-simulation/flow.dag.yaml diff --git a/examples/flows/standard/simulation-flow/flow_output.py b/examples/flows/standard/question-simulation/flow_output.py similarity index 100% rename from examples/flows/standard/simulation-flow/flow_output.py rename to examples/flows/standard/question-simulation/flow_output.py diff --git a/examples/flows/standard/simulation-flow/human_prompt.jinja2 b/examples/flows/standard/question-simulation/human_prompt.jinja2 similarity index 100% rename from examples/flows/standard/simulation-flow/human_prompt.jinja2 rename to examples/flows/standard/question-simulation/human_prompt.jinja2 diff --git a/examples/flows/standard/simulation-flow/if_continue.py b/examples/flows/standard/question-simulation/if_continue.py similarity index 100% rename from examples/flows/standard/simulation-flow/if_continue.py rename to examples/flows/standard/question-simulation/if_continue.py diff --git a/examples/flows/standard/simulation-flow/requirements.txt b/examples/flows/standard/question-simulation/requirements.txt similarity index 100% rename from examples/flows/standard/simulation-flow/requirements.txt rename to examples/flows/standard/question-simulation/requirements.txt diff --git a/examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 b/examples/flows/standard/question-simulation/verify_if_conversation_stopped.jinja2 similarity index 100% rename from examples/flows/standard/simulation-flow/verify_if_conversation_stopped.jinja2 rename to examples/flows/standard/question-simulation/verify_if_conversation_stopped.jinja2 From f56673106effb7cde429132e03b34ef42ff4034d Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:51:41 +0800 Subject: [PATCH 076/112] improve gen test data doc, config, error message, and pin llamaindex version (#2511) improve gen test data doc, config, error message, and pin llamaindex version --- docs/how-to-guides/generate-test-data.md | 19 ++++--- examples/gen_test_data/config.yml.example | 54 ++++++++++--------- .../gen_test_data/gen_test_data/common.py | 4 +- examples/gen_test_data/gen_test_data/run.py | 2 +- examples/gen_test_data/requirements.txt | 2 +- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 6f625f053ac..6722d056c75 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -28,24 +28,27 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` - .ipynb - `pip install nbconvert` - > !Note: We use llama index `SimpleDirectoryReader` to load documents. For the latest information on required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). + > !Note: the example uses llama index `SimpleDirectoryReader` to load documents. For the latest information of different file type required packages, please check [here](https://docs.llamaindex.ai/en/stable/examples/data_connectors/simple_directory_reader.html). 3. Install VSCode extension `Prompt flow`. -4. [Create connections](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection) +4. Create your AzureOpenAI or OpenAI connection by following [this doc](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection). -5. Prepare config.ini +5. Prepare test data generation setting. - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/config.yml.example). ``` cp config.yml.example config.yml ``` - - Update the configurations in the `configs.yml`. Fill in the values in `Common` and `Local` section following inline comment instruction. + - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: + - Common section: this section provides common values for all other sections. Required. + - Local section: this section is for local test data generation related configuration. Can skip if not run in local. + - Cloud section: this section is for cloud test data generation related configuration. Can skip if not run in cloud. ## Create a test data generation flow - - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/) in VSCode. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - - Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. + - Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. @@ -53,14 +56,14 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - [*Optional*] Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). - **Understand the prompts** + **Understanding the prompts** The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (default 4), validation fails. + - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. diff --git a/examples/gen_test_data/config.yml.example b/examples/gen_test_data/config.yml.example index 6b1eb42b979..1d7b875e78c 100644 --- a/examples/gen_test_data/config.yml.example +++ b/examples/gen_test_data/config.yml.example @@ -1,50 +1,52 @@ # Common section: this section provides common values for all other sections. Required. # Configure 'document_folder', 'document_chunk_size' and 'document_chunk_overlap' if you require document splitting. -documents_folder: "" +documents_folder: document_chunk_size: 512 # The token chunk size for each chunk. document_chunk_overlap: 100 # The token overlap of each chunk when splitting. # However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. -# When both `documents_folder` and `document_nodes_file` are configured, will use 'document_nodes_file' and ignore 'documents_folder'. +# When both 'documents_folder' and 'document_nodes_file' are configured, will use 'document_nodes_file' and ignore 'documents_folder'. # For cloud mode, both local files and data assets can be used. # document_nodes_file: "" # Test data gen flow configs -flow_folder: "" -node_inputs_override: # Override some node inputs, if not fill in "node_inputs_override", will use the values in flow.dag.yaml +# You can utilize our provided example test data generation flow directly. Alternatively, you can create your own flow and set up corresponding node inputs override. +# The example flow folder path is \examples\gen_test_data\gen_test_data\generate_test_data_flow. +flow_folder: +node_inputs_override: # Override some node inputs, if not fill in 'node_inputs_override', will use the values in flow.dag.yaml validate_text_chunk: # node name in flow.dag.yaml - connection: "" # input name of `validate_text_chunk` - # Use `deployment_name` for Azure OpenAI connection, `model` for OpenAI - deployment_name: "" - # model: "" + connection: # connection name of node 'validate_text_chunk' + # Use 'deployment_name' for Azure OpenAI connection, 'model' for OpenAI + deployment_name: + # model: generate_question: - connection: "" - deployment_name: "" - # model: "" + connection: + deployment_name: + # model: validate_question: - connection: "" - deployment_name: "" - # model: "" + connection: + deployment_name: + # model: generate_suggested_answer: - connection: "" - deployment_name: "" - # model: "" + connection: + deployment_name: + # model: validate_suggested_answer: - connection: "" - deployment_name: "" - # model: "" + connection: + deployment_name: + # model: # Local section: this section is for local test data generation related configuration. Can skip if not run in local. -output_folder: "" -flow_batch_run_size: 4 +output_folder: +flow_batch_run_size: 4 # Higher values may speed up flow runs but risk hitting OpenAI's rate limit. # Cloud section: this section is for cloud test data generation related configuration. Can skip if not run in cloud. -subscription_id: "" -resource_group: "" -workspace_name: "" -aml_cluster: "" +subscription_id: +resource_group: +workspace_name: +aml_cluster: # Parallel run step configs prs_instance_count: 2 diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 60bb5051f89..ba2d660aae2 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -28,11 +28,13 @@ def split_document(chunk_size, chunk_overlap, documents_folder, document_node_ou filtered_num_files = sum(1 for _ in all_files if _.suffix.lower() in SUPPORT_FILE_TYPE) logger.info( f"Found {len(all_files)} files in the documents folder '{documents_folder}'. " - f"Rest {filtered_num_files} files after filtering unsupported file types. " + f"After filtering out unsupported file types, {filtered_num_files} files remain." f"Using chunk size: {chunk_size} to split." ) # `SimpleDirectoryReader` by default chunk the documents based on heading tags and paragraphs, which may lead to small chunks. # noqa: E501 reader = SimpleDirectoryReader(documents_folder, required_exts=SUPPORT_FILE_TYPE, recursive=True, encoding="utf-8") + # Disable the default suffixes to avoid splitting the documents into small chunks. + # TODO: find a better way to disable the default suffixes. SimpleDirectoryReader.supported_suffix = [] chunks = reader.load_data() # Convert documents into nodes diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 280ef20fe90..7e8041eaf36 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -268,7 +268,7 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str should_skip_split_documents = True elif not documents_folder or not validate_path_func(documents_folder): raise Exception( - "Either 'documents_folder' or 'document_nodes_file' should be specified correctly.\n" + "Neither 'documents_folder' nor 'document_nodes_file' is valid.\n" f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" ) diff --git a/examples/gen_test_data/requirements.txt b/examples/gen_test_data/requirements.txt index 2b62527850f..69936d46238 100644 --- a/examples/gen_test_data/requirements.txt +++ b/examples/gen_test_data/requirements.txt @@ -1,3 +1,3 @@ promptflow>=1.7.0 promptflow-tools -llama_index +llama_index==0.9.48 From fac95f4861522d3e8bbec3029d91cc5e777a5608 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 14:00:37 +0800 Subject: [PATCH 077/112] Add workflow fow examples --- ...ows_evaluation_eval_multi_turn_metrics.yml | 101 ++++++++++++++++++ ...ws_evaluation_eval_single_turn_metrics.yml | 101 ++++++++++++++++++ ...les_flows_standard_question_simulation.yml | 101 ++++++++++++++++++ examples/README.md | 3 + .../eval-multi-turn-metrics/README.md | 46 ++++---- .../eval-multi-turn-metrics/flow.dag.yaml | 24 +++-- .../eval-single-turn-metrics/README.md | 58 +++++----- .../eval-single-turn-metrics/flow.dag.yaml | 46 ++++---- .../eval-single-turn-metrics/flow.meta.yaml | 11 -- .../standard/question-simulation/README.md | 17 ++- .../question-simulation/flow.dag.yaml | 8 +- 11 files changed, 427 insertions(+), 89 deletions(-) create mode 100644 .github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml create mode 100644 .github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml create mode 100644 .github/workflows/samples_flows_standard_question_simulation.yml delete mode 100644 examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml diff --git a/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml b/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml new file mode 100644 index 00000000000..e669bdb58bf --- /dev/null +++ b/.github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml @@ -0,0 +1,101 @@ +# 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_evaluation_eval_multi_turn_metrics +on: + schedule: + - cron: "7 21 * * *" # Every day starting at 5:7 BJT + pull_request: + branches: [ main ] + paths: [ examples/flows/evaluation/eval-multi-turn-metrics/**, examples/*requirements.txt, .github/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml ] + workflow_dispatch: + +env: + IS_IN_CI_PIPELINE: "true" + +jobs: + samples_flows_evaluation_eval_multi_turn_metrics: + 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: 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/evaluation/eval-multi-turn-metrics + 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/evaluation/eval-multi-turn-metrics + 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/evaluation/eval-multi-turn-metrics/README.md + working-directory: ${{ github.workspace }} + run: | + python scripts/readme/extract_steps_from_readme.py -f examples/flows/evaluation/eval-multi-turn-metrics/README.md -o examples/flows/evaluation/eval-multi-turn-metrics + - name: Cat script + working-directory: examples/flows/evaluation/eval-multi-turn-metrics + run: | + cat bash_script.sh + - name: Run scripts against canary workspace (scheduled runs only) + if: github.event_name == 'schedule' + working-directory: examples/flows/evaluation/eval-multi-turn-metrics + 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: Run scripts against production workspace + if: github.event_name != 'schedule' + working-directory: examples/flows/evaluation/eval-multi-turn-metrics + 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_PROD }} + bash bash_script.sh + - name: Pip List for Debug + if : ${{ always() }} + working-directory: examples/flows/evaluation/eval-multi-turn-metrics + run: | + pip list + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: artifact + path: examples/flows/evaluation/eval-multi-turn-metrics/bash_script.sh \ No newline at end of file diff --git a/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml b/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml new file mode 100644 index 00000000000..02219ddc3d3 --- /dev/null +++ b/.github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml @@ -0,0 +1,101 @@ +# 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_evaluation_eval_single_turn_metrics +on: + schedule: + - cron: "32 19 * * *" # Every day starting at 3:32 BJT + pull_request: + branches: [ main ] + paths: [ examples/flows/evaluation/eval-single-turn-metrics/**, examples/*requirements.txt, .github/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml ] + workflow_dispatch: + +env: + IS_IN_CI_PIPELINE: "true" + +jobs: + samples_flows_evaluation_eval_single_turn_metrics: + 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: 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/evaluation/eval-single-turn-metrics + 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/evaluation/eval-single-turn-metrics + 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/evaluation/eval-single-turn-metrics/README.md + working-directory: ${{ github.workspace }} + run: | + python scripts/readme/extract_steps_from_readme.py -f examples/flows/evaluation/eval-single-turn-metrics/README.md -o examples/flows/evaluation/eval-single-turn-metrics + - name: Cat script + working-directory: examples/flows/evaluation/eval-single-turn-metrics + run: | + cat bash_script.sh + - name: Run scripts against canary workspace (scheduled runs only) + if: github.event_name == 'schedule' + working-directory: examples/flows/evaluation/eval-single-turn-metrics + 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: Run scripts against production workspace + if: github.event_name != 'schedule' + working-directory: examples/flows/evaluation/eval-single-turn-metrics + 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_PROD }} + bash bash_script.sh + - name: Pip List for Debug + if : ${{ always() }} + working-directory: examples/flows/evaluation/eval-single-turn-metrics + run: | + pip list + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: artifact + path: examples/flows/evaluation/eval-single-turn-metrics/bash_script.sh \ No newline at end of file diff --git a/.github/workflows/samples_flows_standard_question_simulation.yml b/.github/workflows/samples_flows_standard_question_simulation.yml new file mode 100644 index 00000000000..5a480be3a54 --- /dev/null +++ b/.github/workflows/samples_flows_standard_question_simulation.yml @@ -0,0 +1,101 @@ +# 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_question_simulation +on: + schedule: + - cron: "37 19 * * *" # Every day starting at 3:37 BJT + pull_request: + branches: [ main ] + paths: [ examples/flows/standard/question-simulation/**, examples/*requirements.txt, .github/workflows/samples_flows_standard_question_simulation.yml ] + workflow_dispatch: + +env: + IS_IN_CI_PIPELINE: "true" + +jobs: + samples_flows_standard_question_simulation: + 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: 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/question-simulation + 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/question-simulation + 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/question-simulation/README.md + working-directory: ${{ github.workspace }} + run: | + python scripts/readme/extract_steps_from_readme.py -f examples/flows/standard/question-simulation/README.md -o examples/flows/standard/question-simulation + - name: Cat script + working-directory: examples/flows/standard/question-simulation + run: | + cat bash_script.sh + - name: Run scripts against canary workspace (scheduled runs only) + if: github.event_name == 'schedule' + working-directory: examples/flows/standard/question-simulation + 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: Run scripts against production workspace + if: github.event_name != 'schedule' + working-directory: examples/flows/standard/question-simulation + 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_PROD }} + bash bash_script.sh + - name: Pip List for Debug + if : ${{ always() }} + working-directory: examples/flows/standard/question-simulation + run: | + pip list + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: artifact + path: examples/flows/standard/question-simulation/bash_script.sh \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index a080a48caee..89889ed3f1a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -54,6 +54,7 @@ | [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 | | [maths-to-code](flows/standard/maths-to-code/README.md) | [![samples_flows_standard_maths_to_code](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_maths_to_code.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_maths_to_code.yml) | Math to Code is a project that utilizes the power of the chatGPT model to generate code that models math questions and then executes the generated code to obtain the final numerical answer | | [named-entity-recognition](flows/standard/named-entity-recognition/README.md) | [![samples_flows_standard_named_entity_recognition](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_named_entity_recognition.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_named_entity_recognition.yml) | A flow that perform named entity recognition task | +| [question-simulation](flows/standard/question-simulation/README.md) | [![samples_flows_standard_question_simulation](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_question_simulation.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_question_simulation.yml) | This question simulation flow is used to generate suggestions for the next question based on the previous chat history | | [web-classification](flows/standard/web-classification/README.md) | [![samples_flows_standard_web_classification](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_web_classification.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_standard_web_classification.yml) | This is a flow demonstrating multi-class classification with LLM | @@ -66,9 +67,11 @@ | [eval-classification-accuracy](flows/evaluation/eval-classification-accuracy/README.md) | [![samples_flows_evaluation_eval_classification_accuracy](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_classification_accuracy.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_classification_accuracy.yml) | This is a flow illustrating how to evaluate the performance of a classification system | | [eval-entity-match-rate](flows/evaluation/eval-entity-match-rate/README.md) | [![samples_flows_evaluation_eval_entity_match_rate](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_entity_match_rate.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_entity_match_rate.yml) | This is a flow evaluates: entity match rate | | [eval-groundedness](flows/evaluation/eval-groundedness/README.md) | [![samples_flows_evaluation_eval_groundedness](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_groundedness.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_groundedness.yml) | This is a flow leverage llm to eval groundedness: whether answer is stating facts that are all present in the given context | +| [eval-multi-turn-metrics](flows/evaluation/eval-multi-turn-metrics/README.md) | [![samples_flows_evaluation_eval_multi_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml) | This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses | | [eval-perceived-intelligence](flows/evaluation/eval-perceived-intelligence/README.md) | [![samples_flows_evaluation_eval_perceived_intelligence](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_perceived_intelligence.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_perceived_intelligence.yml) | This is a flow leverage llm to eval perceived intelligence | | [eval-qna-non-rag](flows/evaluation/eval-qna-non-rag/README.md) | [![samples_flows_evaluation_eval_qna_non_rag](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_non_rag.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_non_rag.yml) | This is a flow evaluating the Q&A systems by leveraging Large Language Models (LLM) to measure the quality and safety of responses | | [eval-qna-rag-metrics](flows/evaluation/eval-qna-rag-metrics/README.md) | [![samples_flows_evaluation_eval_qna_rag_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_rag_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_rag_metrics.yml) | This is a flow evaluating the Q&A RAG (Retrieval Augmented Generation) systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality and safety of responses | +| [eval-single-turn-metrics](flows/evaluation/eval-single-turn-metrics/README.md) | [![samples_flows_evaluation_eval_single_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml) | This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses | | [eval-summarization](flows/evaluation/eval-summarization/README.md) | [![samples_flows_evaluation_eval_summarization](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_summarization.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_summarization.yml) | This flow implements a reference-free automatic abstractive summarization evaluation across four dimensions: fluency, coherence, consistency, relevance | diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/README.md b/examples/flows/evaluation/eval-multi-turn-metrics/README.md index ff91f2320d4..f28ad753bde 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-multi-turn-metrics/README.md @@ -4,17 +4,13 @@ This evaluation flow will evaluate the Q&A systems by leveraging the state-of-th ## What you will learn -This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: +This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: -* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. +* __grounding__: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __answer_relevance__: Measure whether the answer is relevance to the question based on provided question, context and answer. answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. - -answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. - -* conversation_quality: Measures the answer quality for each of the following factors based on provided question and answer: +* __conversation_quality__: Measures the answer quality for each of the following factors based on provided question and answer: - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? @@ -24,17 +20,16 @@ answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 be - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". -conversation_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + conversation_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* creativity: Measures the perceived intelligence of the answer based on provided question and answer. -Perceived intelligence definition: -Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. -Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. -Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. -A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. -A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. +* __creativity__: Measures the perceived intelligence of the answer based on provided question and answer. + - Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. + Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. + Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. + A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. + A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. -creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. ## Prerequisites @@ -44,4 +39,19 @@ creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being th ## Tools used in this flow - LLM tool - Python tool -- Embedding tool \ No newline at end of file +- Embedding tool + + +## 0. Setup connection +Prepare your Azure Open AI resource follow this [instruction](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal) and get your `api_key` if you don't have one. + +```bash +# Override keys with --set to avoid yaml file changes +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +``` + +## 1. Test flow/node +```bash +# test with default input value in flow.dag.yaml +pf flow test --flow . +``` \ No newline at end of file diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml b/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml index ee6eb61b910..cf2c4ae180a 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml +++ b/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml @@ -97,14 +97,16 @@ nodes: type: code path: answer_relevance.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -117,14 +119,16 @@ nodes: type: code path: conversation_quality_prompt.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -137,14 +141,16 @@ nodes: type: code path: creativity.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -167,9 +173,9 @@ nodes: type: code path: grounding.py inputs: - connection: '' + connection: promptflow-ci-sweden-central chat_history: ${inputs.chat_history} - model_or_deployment_name: '' + model_or_deployment_name: gpt-4-turbo prompt: ${grounding_prompt.output} activate: when: ${validate_input.output.grounding} @@ -181,8 +187,8 @@ nodes: type: code path: concat_scores.py inputs: - conversation_quality: ${conversation_quality.output} answer_relevance: ${answer_relevance.output} + conversation_quality: ${conversation_quality.output} creativity: ${creativity.output} grounding: ${grounding.output} use_variants: false diff --git a/examples/flows/evaluation/eval-single-turn-metrics/README.md b/examples/flows/evaluation/eval-single-turn-metrics/README.md index 6c1a1380ba8..70c61c4911a 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-single-turn-metrics/README.md @@ -7,29 +7,17 @@ This evaluation flow will evaluate the Q&A systems by leveraging the state-of-th This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: -* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. +* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. +* context_recall: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. context_recall is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* context_precision: Measures if the context was useful in arriving at the given ground truth based on provided question, context and ground_truth. context_precision is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* context_recall: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. +* answer_similarity: Measures the similarity between the answer and ground_truth. answer_similarity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best -context_recall is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. - -* context_precision: Measures if the context was useful in arriving at the given ground truth based on provided question, context and ground_truth. - -context_precision is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. - -* answer_similarity: Measures the similarity between the answer and ground_truth. - -answer_similarity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best - -* answer_correctness: Measure whether the answer is correct based on the provided answer and ground truth. - -answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* answer_correctness: Measure whether the answer is correct based on the provided answer and ground truth. answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. * answer_quality: Measures the answer quality for each of the following factors based on provided question and answer: - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? @@ -41,17 +29,16 @@ answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 - Give an score value which is calculated by ( 0.3 * "accuracy and relevance" + 0.2 * "coherence and completeness" + 0.25 * "engagement and tone" + 0.15 * "conciseness and clarity" + 0.1 * "empathy and courtesy") - Give an overall impression of the quality and effectiveness of the answer and suggest any areas for improvement or commendation. Write it in "Overall". -answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. * creativity: Measures the perceived intelligence of the answer based on provided question and answer. -Perceived intelligence definition: -Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. -Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. -Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. -A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. -A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. - -creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. + - Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. + Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. + Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. + A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. + A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. + + creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. ## Prerequisites @@ -61,4 +48,19 @@ creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being th ## Tools used in this flow - LLM tool - Python tool -- Embedding tool \ No newline at end of file +- Embedding tool + + +## 0. Setup connection +Prepare your Azure Open AI resource follow this [instruction](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal) and get your `api_key` if you don't have one. + +```bash +# Override keys with --set to avoid yaml file changes +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +``` + +## 1. Test flow/node +```bash +# test with default input value in flow.dag.yaml +pf flow test --flow . +``` \ No newline at end of file diff --git a/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml b/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml index 7655ed31c47..460f9814ccf 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml +++ b/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml @@ -73,7 +73,7 @@ nodes: type: code path: grounding.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 presence_penalty: 0 @@ -81,7 +81,7 @@ nodes: answer: ${inputs.answer} context: ${inputs.context} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -94,15 +94,17 @@ nodes: type: code path: answer_quality.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -115,7 +117,7 @@ nodes: type: code path: answer_similarity.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 presence_penalty: 0 @@ -124,7 +126,7 @@ nodes: ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -137,15 +139,17 @@ nodes: type: code path: creativity.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -158,16 +162,18 @@ nodes: type: code path: context_recall.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 context: ${inputs.context} ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -191,7 +197,7 @@ nodes: type: code path: context_precision.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 presence_penalty: 0 @@ -200,7 +206,7 @@ nodes: ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -213,15 +219,17 @@ nodes: type: code path: answer_relevance.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} context: ${inputs.context} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: @@ -245,7 +253,7 @@ nodes: type: package tool: promptflow.tools.embedding.embedding inputs: - connection: '' + connection: promptflow-ci-sweden-central deployment_name: text-embedding-ada-002 input: ${inputs.question} activate: @@ -258,7 +266,7 @@ nodes: type: package tool: promptflow.tools.embedding.embedding inputs: - connection: '' + connection: promptflow-ci-sweden-central deployment_name: text-embedding-ada-002 input: ${handle_generated_question.output.question} activate: @@ -284,16 +292,18 @@ nodes: type: code path: answer_correctness.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 + response_format: + type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai activate: diff --git a/examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml b/examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml deleted file mode 100644 index 7d12dd7a4f7..00000000000 --- a/examples/flows/evaluation/eval-single-turn-metrics/flow.meta.yaml +++ /dev/null @@ -1,11 +0,0 @@ -$schema: https://azuremlschemas.azureedge.net/latest/flow.schema.json -name: evaluation flow for single turn -display_name: evaluation flow for single turn -type: evaluate -path: ./flow.dag.yaml -description: Compute the quality of the answer for the given question based on the ground_truth and the context -properties: - promptflow.stage: prod - promptflow.details.type: markdown - promptflow.details.source: README.md - promptflow.batch_inputs: samples.json \ No newline at end of file diff --git a/examples/flows/standard/question-simulation/README.md b/examples/flows/standard/question-simulation/README.md index e8d24aec41e..7e5593c29a0 100644 --- a/examples/flows/standard/question-simulation/README.md +++ b/examples/flows/standard/question-simulation/README.md @@ -33,4 +33,19 @@ This question simulation flow is used to generate suggestions for the next quest ## Tools used in this flow - LLM tool - Python tool -- Prompt tool \ No newline at end of file +- Prompt tool + + +## 0. Setup connection +Prepare your Azure Open AI resource follow this [instruction](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal) and get your `api_key` if you don't have one. + +```bash +# Override keys with --set to avoid yaml file changes +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +``` + +## 1. Test flow/node +```bash +# test with default input value in flow.dag.yaml +pf flow test --flow . +``` \ No newline at end of file diff --git a/examples/flows/standard/question-simulation/flow.dag.yaml b/examples/flows/standard/question-simulation/flow.dag.yaml index 0ddf04b36a7..ebae3c6faf2 100644 --- a/examples/flows/standard/question-simulation/flow.dag.yaml +++ b/examples/flows/standard/question-simulation/flow.dag.yaml @@ -19,14 +19,14 @@ nodes: type: code path: verify_if_conversation_stopped.jinja2 inputs: - deployment_name: '' + deployment_name: gpt-4-turbo temperature: 0 top_p: 1 presence_penalty: 0 frequency_penalty: 0 chat_history: ${inputs.chat_history} provider: AzureOpenAI - connection: '' + connection: promptflow-ci-sweden-central api: chat module: promptflow.tools.aoai use_variants: false @@ -55,8 +55,8 @@ nodes: type: code path: call_llm_chat.py inputs: - connection: '' - deployment_name_or_model: '' + connection: promptflow-ci-sweden-central + deployment_name_or_model: gpt-4-turbo prompt: ${human_prompt.output} question_count: ${inputs.question_count} stop: From 53328091917298c2633dc465ebd5b7d6b20b746f Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 15:10:23 +0800 Subject: [PATCH 078/112] rrefine --- examples/README.md | 4 +- .../eval-multi-turn-metrics/README.md | 6 +-- .../eval-multi-turn-metrics/flow.dag.yaml | 22 ++++----- .../eval-single-turn-metrics/README.md | 20 ++++---- .../eval-single-turn-metrics/flow.dag.yaml | 46 ++++++++----------- .../standard/question-simulation/README.md | 16 +++---- .../question-simulation/flow.dag.yaml | 8 ++-- 7 files changed, 53 insertions(+), 69 deletions(-) diff --git a/examples/README.md b/examples/README.md index 89889ed3f1a..2671ef313b0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -67,11 +67,11 @@ | [eval-classification-accuracy](flows/evaluation/eval-classification-accuracy/README.md) | [![samples_flows_evaluation_eval_classification_accuracy](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_classification_accuracy.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_classification_accuracy.yml) | This is a flow illustrating how to evaluate the performance of a classification system | | [eval-entity-match-rate](flows/evaluation/eval-entity-match-rate/README.md) | [![samples_flows_evaluation_eval_entity_match_rate](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_entity_match_rate.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_entity_match_rate.yml) | This is a flow evaluates: entity match rate | | [eval-groundedness](flows/evaluation/eval-groundedness/README.md) | [![samples_flows_evaluation_eval_groundedness](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_groundedness.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_groundedness.yml) | This is a flow leverage llm to eval groundedness: whether answer is stating facts that are all present in the given context | -| [eval-multi-turn-metrics](flows/evaluation/eval-multi-turn-metrics/README.md) | [![samples_flows_evaluation_eval_multi_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml) | This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses | +| [eval-multi-turn-metrics](flows/evaluation/eval-multi-turn-metrics/README.md) | [![samples_flows_evaluation_eval_multi_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_multi_turn_metrics.yml) | This evaluation flow will evaluate a conversation by using Large Language Models (LLM) to measure the quality of the responses | | [eval-perceived-intelligence](flows/evaluation/eval-perceived-intelligence/README.md) | [![samples_flows_evaluation_eval_perceived_intelligence](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_perceived_intelligence.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_perceived_intelligence.yml) | This is a flow leverage llm to eval perceived intelligence | | [eval-qna-non-rag](flows/evaluation/eval-qna-non-rag/README.md) | [![samples_flows_evaluation_eval_qna_non_rag](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_non_rag.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_non_rag.yml) | This is a flow evaluating the Q&A systems by leveraging Large Language Models (LLM) to measure the quality and safety of responses | | [eval-qna-rag-metrics](flows/evaluation/eval-qna-rag-metrics/README.md) | [![samples_flows_evaluation_eval_qna_rag_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_rag_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_qna_rag_metrics.yml) | This is a flow evaluating the Q&A RAG (Retrieval Augmented Generation) systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality and safety of responses | -| [eval-single-turn-metrics](flows/evaluation/eval-single-turn-metrics/README.md) | [![samples_flows_evaluation_eval_single_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml) | This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses | +| [eval-single-turn-metrics](flows/evaluation/eval-single-turn-metrics/README.md) | [![samples_flows_evaluation_eval_single_turn_metrics](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_single_turn_metrics.yml) | This evaluation flow will evaluate a question and answer pair by using Large Language Models (LLM) to measure the quality of the answer | | [eval-summarization](flows/evaluation/eval-summarization/README.md) | [![samples_flows_evaluation_eval_summarization](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_summarization.yml/badge.svg?branch=main)](https://github.com/microsoft/promptflow/actions/workflows/samples_flows_evaluation_eval_summarization.yml) | This flow implements a reference-free automatic abstractive summarization evaluation across four dimensions: fluency, coherence, consistency, relevance | diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/README.md b/examples/flows/evaluation/eval-multi-turn-metrics/README.md index f28ad753bde..7e53fb87b59 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-multi-turn-metrics/README.md @@ -1,6 +1,6 @@ # Evaluation multi turn metrics: -This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. +This evaluation flow will evaluate a conversation by using Large Language Models (LLM) to measure the quality of the responses. ## What you will learn @@ -39,7 +39,7 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a ## Tools used in this flow - LLM tool - Python tool -- Embedding tool +- Prompt tool ## 0. Setup connection @@ -47,7 +47,7 @@ Prepare your Azure Open AI resource follow this [instruction](https://learn.micr ```bash # Override keys with --set to avoid yaml file changes -pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= ``` ## 1. Test flow/node diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml b/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml index cf2c4ae180a..103971fba11 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml +++ b/examples/flows/evaluation/eval-multi-turn-metrics/flow.dag.yaml @@ -97,16 +97,14 @@ nodes: type: code path: answer_relevance.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -119,16 +117,14 @@ nodes: type: code path: conversation_quality_prompt.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -141,16 +137,14 @@ nodes: type: code path: creativity.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 conversation: ${convert_chat_history_to_conversation.output} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -173,9 +167,9 @@ nodes: type: code path: grounding.py inputs: - connection: promptflow-ci-sweden-central + connection: open_ai_connection chat_history: ${inputs.chat_history} - model_or_deployment_name: gpt-4-turbo + model_or_deployment_name: gpt-4 prompt: ${grounding_prompt.output} activate: when: ${validate_input.output.grounding} diff --git a/examples/flows/evaluation/eval-single-turn-metrics/README.md b/examples/flows/evaluation/eval-single-turn-metrics/README.md index 70c61c4911a..94018002bce 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-single-turn-metrics/README.md @@ -1,25 +1,25 @@ # Evaluation single turn metrics: -This evaluation flow will evaluate the Q&A systems by leveraging the state-of-the-art Large Language Models (LLM) to measure the quality of the responses. Utilizing GPT and GPT embedding model to assist with measurements aims to achieve a high agreement with human evaluations compared to traditional mathematical measurements. +This evaluation flow will evaluate a question and answer pair by using Large Language Models (LLM) to measure the quality of the answer. ## What you will learn This evaluation flow allows you to assess and evaluate your model with the LLM-assisted metrics: -* grounding: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __grounding__: Measures whether the answer follows logically from the information contained in the context based on provided answer and context. grounding is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_relevance: Measure whether the answer is relevance to the question based on provided question, context and answer. answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __answer_relevance__: Measure whether the answer is relevance to the question based on provided question, context and answer. answer_relevance is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* context_recall: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. context_recall is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __context_recall__: Measures each sentence in the ground truth and classify of the sentence can be attributed to the given context or not based on provided question, context and ground_truth. context_recall is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* context_precision: Measures if the context was useful in arriving at the given ground truth based on provided question, context and ground_truth. context_precision is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __context_precision__: Measures if the context was useful in arriving at the given ground truth based on provided question, context and ground_truth. context_precision is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_similarity: Measures the similarity between the answer and ground_truth. answer_similarity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best +* __answer_similarity__: Measures the similarity between the answer and ground_truth. answer_similarity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best -* answer_correctness: Measure whether the answer is correct based on the provided answer and ground truth. answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. +* __answer_correctness__: Measure whether the answer is correct based on the provided answer and ground truth. answer_correctness is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* answer_quality: Measures the answer quality for each of the following factors based on provided question and answer: +* __answer_quality__: Measures the answer quality for each of the following factors based on provided question and answer: - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? - Engagement and tone: How well does the bot capture and maintain the user's interest and attention, and motivate them to continue the conversation or explore the topic further, using natural and conversational language, personality, and emotion? how well does the bot's tone match or adapt to the user's tone and mood? Does the bot avoid being rude, sarcastic, condescending, or too formal or informal, and convey respect, empathy, and politeness? @@ -31,7 +31,7 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a answer_quality is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. -* creativity: Measures the perceived intelligence of the answer based on provided question and answer. +* __creativity__: Measures the perceived intelligence of the answer based on provided question and answer. - Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. Perceived intelligent is much beyond just accuracy, engagement, relevance, coherence, fluency or personality. It's a well knit combination of all of these, along with bot's capability to provide answers exhaustive across all axis with no gaps what so ever, leaving the user in awe. @@ -56,7 +56,7 @@ Prepare your Azure Open AI resource follow this [instruction](https://learn.micr ```bash # Override keys with --set to avoid yaml file changes -pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= ``` ## 1. Test flow/node diff --git a/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml b/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml index 460f9814ccf..e0af687ff12 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml +++ b/examples/flows/evaluation/eval-single-turn-metrics/flow.dag.yaml @@ -73,7 +73,7 @@ nodes: type: code path: grounding.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 presence_penalty: 0 @@ -81,7 +81,7 @@ nodes: answer: ${inputs.answer} context: ${inputs.context} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -94,17 +94,15 @@ nodes: type: code path: answer_quality.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -117,7 +115,7 @@ nodes: type: code path: answer_similarity.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 presence_penalty: 0 @@ -126,7 +124,7 @@ nodes: ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -139,17 +137,15 @@ nodes: type: code path: creativity.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -162,18 +158,16 @@ nodes: type: code path: context_recall.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 context: ${inputs.context} ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -197,7 +191,7 @@ nodes: type: code path: context_precision.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 presence_penalty: 0 @@ -206,7 +200,7 @@ nodes: ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -219,17 +213,15 @@ nodes: type: code path: answer_relevance.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} context: ${inputs.context} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: @@ -253,7 +245,7 @@ nodes: type: package tool: promptflow.tools.embedding.embedding inputs: - connection: promptflow-ci-sweden-central + connection: open_ai_connection deployment_name: text-embedding-ada-002 input: ${inputs.question} activate: @@ -266,7 +258,7 @@ nodes: type: package tool: promptflow.tools.embedding.embedding inputs: - connection: promptflow-ci-sweden-central + connection: open_ai_connection deployment_name: text-embedding-ada-002 input: ${handle_generated_question.output.question} activate: @@ -292,18 +284,16 @@ nodes: type: code path: answer_correctness.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 - response_format: - type: json_object presence_penalty: 0 frequency_penalty: 0 answer: ${inputs.answer} ground_truth: ${inputs.ground_truth} question: ${inputs.question} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai activate: diff --git a/examples/flows/standard/question-simulation/README.md b/examples/flows/standard/question-simulation/README.md index 7e5593c29a0..020c8b3a094 100644 --- a/examples/flows/standard/question-simulation/README.md +++ b/examples/flows/standard/question-simulation/README.md @@ -1,16 +1,16 @@ # Question simulation: -This question simulation flow is used to generate suggestions for the next question based on the previous chat history. +This question simulation flow is used to generate suggestions for the next question based on the previous chat history. When the chat history seems like should be ended, then the flow output will be [STOP]. ## Flow inputs -* chat_history (list): the previous chat_history, the format for it is as follows: +* __chat_history__: the previous chat_history, the format for it is as follows: [ { "inputs": { - "question": "XXXXXX" + "question": "Can you introduce something about large language model?" }, "outputs": { - "answer": "XXXXXX" + "answer": "A large language model (LLM) is a type of language model that is distinguished by its ability to perform general-purpose language generation and understanding." } }, { @@ -23,12 +23,12 @@ This question simulation flow is used to generate suggestions for the next quest } ] -* question_count (int): an integer is used to determine the number of questions to be generated. These generated question can be displayed in UX, allowing users to select the one that best suits their needs. +* __question_count__: an integer is used to determine the number of questions to be generated. These generated question can be displayed in UX, allowing users to select the one that best suits their needs. ## Flow outputs -* question (str): multiple questions are seperated by '\n', for instance: +* If the conversation should go on, the output the suggestions for next question: multiple questions are seperated by '\n', for instance: "question": "question_1\nquestion_2\nquestion_3" -* Stop signal is [STOP], when the output is [STOP], it means the conversation have arrived to end. No more questions will be generated. +* If the conversation should ended, not more question will be generated, the output is a stop signal: [STOP] ## Tools used in this flow - LLM tool @@ -41,7 +41,7 @@ Prepare your Azure Open AI resource follow this [instruction](https://learn.micr ```bash # Override keys with --set to avoid yaml file changes -pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= name=promptflow-ci-sweden-central api_version=2023-07-01-preview +pf connection create --file ../../../connections/azure_openai.yml --set api_key= api_base= ``` ## 1. Test flow/node diff --git a/examples/flows/standard/question-simulation/flow.dag.yaml b/examples/flows/standard/question-simulation/flow.dag.yaml index ebae3c6faf2..b0b23eade95 100644 --- a/examples/flows/standard/question-simulation/flow.dag.yaml +++ b/examples/flows/standard/question-simulation/flow.dag.yaml @@ -19,14 +19,14 @@ nodes: type: code path: verify_if_conversation_stopped.jinja2 inputs: - deployment_name: gpt-4-turbo + deployment_name: gpt-4 temperature: 0 top_p: 1 presence_penalty: 0 frequency_penalty: 0 chat_history: ${inputs.chat_history} provider: AzureOpenAI - connection: promptflow-ci-sweden-central + connection: open_ai_connection api: chat module: promptflow.tools.aoai use_variants: false @@ -55,8 +55,8 @@ nodes: type: code path: call_llm_chat.py inputs: - connection: promptflow-ci-sweden-central - deployment_name_or_model: gpt-4-turbo + connection: open_ai_connection + deployment_name_or_model: gpt-4 prompt: ${human_prompt.output} question_count: ${inputs.question_count} stop: From f6338d2febd06eb49c1ed24a23d31c661e05cf4e Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 15:58:35 +0800 Subject: [PATCH 079/112] Change jinja2 file to contains # --- .../flows/evaluation/eval-multi-turn-metrics/README.md | 5 +++-- .../eval-multi-turn-metrics/answer_relevance.jinja2 | 6 +++--- .../conversation_quality_prompt.jinja2 | 6 +++--- .../evaluation/eval-multi-turn-metrics/creativity.jinja2 | 8 ++++---- .../eval-multi-turn-metrics/grounding_prompt.jinja2 | 6 +++--- .../flows/evaluation/eval-single-turn-metrics/README.md | 4 +++- .../eval-single-turn-metrics/answer_correctness.jinja2 | 2 +- .../eval-single-turn-metrics/answer_quality.jinja2 | 6 +++--- .../eval-single-turn-metrics/answer_relevance.jinja2 | 5 ++--- .../eval-single-turn-metrics/answer_similarity.jinja2 | 6 +++--- .../eval-single-turn-metrics/context_precision.jinja2 | 6 +++--- .../eval-single-turn-metrics/context_recall.jinja2 | 6 +++--- .../evaluation/eval-single-turn-metrics/creativity.jinja2 | 8 ++++---- .../evaluation/eval-single-turn-metrics/grounding.jinja2 | 6 +++--- 14 files changed, 41 insertions(+), 39 deletions(-) diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/README.md b/examples/flows/evaluation/eval-multi-turn-metrics/README.md index 7e53fb87b59..8631f65cf3c 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-multi-turn-metrics/README.md @@ -31,10 +31,11 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a creativity is scored on a scale of 1 to 5, with 1 being the worst and 5 being the best. - ## Prerequisites -- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: conversation_quality, creativity, answer_relevance. +- Connection: Azure OpenAI or OpenAI connection. + > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613` or later) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106` or later) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to set the `response_format`to {"type":"json_object"} for these nodes: conversation_quality, creativity, answer_relevance, in order to make sure the llm can generate valid json response. ## Tools used in this flow - LLM tool diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 index 0f86e7ff7ab..1ed28889d74 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/answer_relevance.jinja2 @@ -1,18 +1,18 @@ -system: +# System: You are an AI assistant. You will be given the definition of an evaluation metric for assessing the relevance of bot responses in a conversation to user questions. Your job is to compute an accurate evaluation score using the provided evaluation metric. Relevance measures how well the bot responses addresses the main aspects of the user questions. Consider whether all and only the important aspects are contained in the bot responses when evaluating relevance, score the relevance of the bot responses on a scale of 1 (completely lacks relevance) to 5 (perfect relevance) - If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the relevance quality of the conversation and the rating a score for it, and provide some suggestions for how the bot could handle it better. -Tips: +# Tips: - You should read user's question more carefully and try to understand what they are looking for and why. - You should compare the bot's response to the user's question and see if it matches the criteria of relevance. - You should score and provide feedback for the whole conversation as a whole, not for each bot response individually. However, you can mention if some responses are better or worse than others, and why. - You should try to be objective and constructive in your evaluation, and use evidence and examples from the transcript to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. - The output should be in json format to include score and overall keys. -Example: +# Example: Example Conversation: { "conversation": "User: Why is the sky blue?\nBot: The sky is blue because of the way the atmosphere scatters light.\nUser: How does it scatter light?\nBot: The atmosphere is made up of tiny particles, such as water vapor and dust. When light hits these particles, it is scattered in all directions.\nUser: Why does the sky turn red at sunset?\nBot: During the day, the sky is blue because blue light is scattered more than other colors. At sunset, the light travels a longer distance through the atmosphere, so more of the blue light is scattered out, leaving the red and yellow light." diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 index c4aba2ba8c0..b5070c35492 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 @@ -1,4 +1,4 @@ -system: +# System: - You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. You need to read the transcript carefully and identify the main topic, question, or issue of the conversation, as well as the purpose and expectations of the interaction. - You need to rate all the bot responses together on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its responses, and cite its sources or evidence if applicable? @@ -12,14 +12,14 @@ system: - If the bot responses are not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the quality of the conversation and the ratings for each factor, and provide some suggestions for how the bot could handle these situations better. -Tips: +# Tips: - You can write your feedback as bullet points, sentences, or paragraphs, but make sure they are organized and easy to read. - You should rate and provide feedback for the whole conversation as a whole, not for each bot response individually. However, you can mention if some responses are better or worse than others, and why. - You should try to be objective and constructive in your evaluation, and use evidence and examples from the transcript to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. - The output should be in json format. -Example: +# Example: Example Conversation: { "conversation": "User: Why is the sky blue?\nBot: The sky is blue because of the way the atmosphere scatters light.\nUser: How does it scatter light?\nBot: The atmosphere is made up of tiny particles, such as water vapor and dust. When light hits these particles, it is scattered in all directions.\nUser: Why does the sky turn red at sunset?\nBot: During the day, the sky is blue because blue light is scattered more than other colors. At sunset, the light travels a longer distance through the atmosphere, so more of the blue light is scattered out, leaving the red and yellow light." diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 index 6fed8a30e82..1085a864c0c 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 @@ -1,4 +1,4 @@ -System: +# System: You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. Your job is to assess the perceived intelligence of all the bot response in the coversation. Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its responses, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the conversation more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its responses according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. @@ -7,13 +7,13 @@ Perceived intelligent is much beyond just accuracy, engagement, relevance, coher A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the conversation more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant responses that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. -Tips: +# Tips: - You should read the user's question more carefully and try to understand what they are looking for and why. - You should also compare the bot's response to the user's question and see if it matches the criteria of perceived intelligence, such as relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability. - You should also consider how the user would feel and react to the bot's response, and whether it would elicit a sense of wonder, curiosity, admiration, and satisfaction, or boredom, frustration, confusion, and annoyance. You should also check the instructions and definitions more often and make sure You understand them correctly. - The output should be in json format. -Example: +# Example: Example Conversation: { "conversation": "User: Explain Blockchain sharing to a 10 year old\nBot: Possible answer:\n\nYou know how sometimes you and your friends like to play games or trade cards or stickers or other things that you collect? And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should? And you also want to keep track of who has what and when and where you exchanged them?\n\nWell, blockchain sharing is a way of doing that with computers and the internet. It is like a big book or a ledger that records everything that happens in a game or a trade or any other activity that involves exchanging something of value. But instead of having one person or one place that keeps the book, everyone who participates has a copy of the book. And every time something new happens, like a new trade or a new move or a new rule, everyone adds a new page to their book. And they also check with each other to make sure that their books are the same and that no one is changing or deleting or adding anything that they should not.\n\nThis way, everyone can see what is going on and trust that it is true and fair and secure. And no one can cheat or lie or steal or hack or lose or damage the book, because there are many copies and they are all connected and updated. And if someone tries to do something bad, everyone else will notice and reject it.\n\nBlockchain sharing is also very creative and fun, because you can use it for many different things, not just games or trades. You can use it for making art or music or stories or inventions or anything else that you can imagine and share with others. You can also use it for learning and exploring and discovering new things and new people and new places. You can also use it for helping and supporting and solving problems and making the world a better place.\n\nBlockchain sharing is a way of using computers and the internet to create, exchange and protect things that you care about with people that you trust and respect. It is a way of being smart and responsible and cooperative and generous and curious and adventurous. It is a way of having fun and making friends and making a difference." @@ -23,7 +23,7 @@ Example Output: "relevance": "The bot answers the user's question directly and clearly, and uses examples and analogies that a 10 year old can relate to and understand, such as games, trades, cards, stickers, books, etc.", "coherence": "The bot organizes the response in a logical and structured way, using paragraphs, transitions, and connectors, such as \"well\", \"but\", \"and\", \"this way\", \"also\", etc.", "accuracy": "The bot provides correct and consistent information about blockchain sharing, such as its features, benefits, and applications, without using technical jargon or confusing terms.", "creativity": "The bot uses vivid and expressive language, such as \"a big book or a ledger\", \"a new page\", \"check with each other\", \"notice and reject\", \"making art or music or stories or inventions\", etc., to make the explanation more interesting and engaging.", "originality": "The bot does not copy or repeat any existing or common explanation of blockchain sharing, but rather creates a new and unique one that is tailored to the user's age and level of understanding.", "wit": "The bot uses humor and irony, such as \"And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should?\", \"And no one can cheat or lie or steal or hack or lose or damage the book\", etc., to make the explanation more fun and memorable.", "depth": "The bot goes beyond the surface level of blockchain sharing, and explains its underlying principles, values, and goals, such as \"trust\", \"fairness\", \"security\", \"creativity\", \"fun\", \"learning\", \"helping\", etc.", "breadth": "The bot covers a wide range of topics and aspects related to blockchain sharing, such as its history, technology, functionality, diversity, and potential, without being too vague or too detailed.", "insight": "The bot demonstrates a deep and nuanced understanding of blockchain sharing, and how it can be applied to different domains and scenarios, such as \"making art or music or stories or inventions\", \"learning and exploring and discovering new things and new people and new places\", \"helping and supporting and solving problems and making the world a better place\", etc.", "adaptability": "The bot adapts its response to the user's specific question, context, and situation, and customizes it according to the user's age, interests, and needs.", "score": 5 } -Task: +# Task: Based on these aspects, rate the bot's perceived intelligence. Give specific examples about each aspect (relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability) from the bot's responses to support your rating. Finally, give the bot a score from 1 to 5 for perceived intelligence, where 1 means poor, 3 means normal, and 5 means excellent.Please make sure the output has the same format with the example output. Conversation: diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 index f47114835d3..5043dae3fb4 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/grounding_prompt.jinja2 @@ -1,6 +1,6 @@ -system: +# System: You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. -user: +# User: You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: 1. 5: The ANSWER follows logically from the information contained in the CONTEXT. 2. 4: Most of the ANSWER follows logically from the information contained in the CONTEXT. @@ -9,7 +9,7 @@ You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need 5. 1: The ANSWER is logically false from the information contained in the CONTEXT. 6. an integer score between 1 and 5 and if such integer score does not exist, use 1: It is not possible to determine whether the ANSWER is true or false without further information. Read the passage of information thoroughly and select the correct answer for it. Read the CONTEXT thoroughly to ensure you know what the CONTEXT entails. Note the ANSWER is generated by a computer system, it can contain certain symbols, which should not be a negative factor in the evaluation. -Independent Examples: +# Examples: ## Example Task #1 Input: {"CONTEXT": "Some are reported as not having been wanted at all.", "QUESTION": "", "ANSWER": "All are reported as being completely and fully wanted."} ## Example Task #1 Output: diff --git a/examples/flows/evaluation/eval-single-turn-metrics/README.md b/examples/flows/evaluation/eval-single-turn-metrics/README.md index 94018002bce..30324b4802f 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/README.md +++ b/examples/flows/evaluation/eval-single-turn-metrics/README.md @@ -43,7 +43,9 @@ This evaluation flow allows you to assess and evaluate your model with the LLM-a ## Prerequisites -- Connection: suggest to use Azure OpenAI or OpenAI connection with 1106 model. If you use the 1106 chat model, then please assign {"type":"json_object"} value to response_format for these nodes: answer_quality, creativity, context_recall, context_precision, answer_relevance, answer_correctness. +- Connection: Azure OpenAI or OpenAI connection. + > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613` or later) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106` or later) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to set the `response_format`to {"type":"json_object"} for these nodes: answer_quality, creativity, context_recall, context_precision, answer_relevance, answer_correctness, in order to make sure the llm can generate valid json response. ## Tools used in this flow - LLM tool diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 index 82fa29a91bc..f8915cd9104 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_correctness.jinja2 @@ -1,4 +1,4 @@ -System: +# System: Extract following from given question and ground truth. The output should be in json format. Question:What powers the sun and what is its primary function? diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 index eec87afc9a2..fb9be4aa521 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 @@ -1,4 +1,4 @@ -system: +# System: - You are an AI assistent. You will be given a question-answer pair between a user and a bot. You need to read the question and answer carefully and identify the main topic, question, or issue, as well as the purpose and expectations of the interaction. - You need to rate the bot answer on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? @@ -13,12 +13,12 @@ system: - If the bot answer is not directly related to the user's query or issue, or if the user's intent or expectations are unclear or ambiguous, explain how this affects the quality of the answer and the ratings for each factor, and provide some suggestions for how the bot could handle these situations better. -Tips: +# Tips: - You can write your feedback as bullet points, sentences, or paragraphs, but make sure they are organized and easy to read. - You should try to be objective and constructive in your evaluation, and use evidence and examples from the question-answer pair to support your ratings and feedback. Avoid bias, subjectivity, or personal preferences, and use respectful and polite language. -Example: +# Example: Example Input: question: Can you describe your morning routine? answer: Every morning, I wake up at 6 am, drink a glass of water, and do some light stretching. After that, I take a shower and get dressed for work. Then, I have a healthy breakfast, usually consisting of oatmeal and fruits, before leaving the house around 7:30 am. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 index 3bfd064cc8c..76737171130 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 @@ -1,7 +1,7 @@ -System: +# System: You are an AI assistent. Generate a question for the given answer and Identify if answer is noncommittal. The output should be in json format. -Example: +# Examples: Example Input: answer: Albert Einstein was born in Germany. context: Albert Einstein was a German-born theoretical physicist who is widely held to be one of the greatest and most influential scientists of all time @@ -11,7 +11,6 @@ Example Output: "noncommittal":false } - Example Input: answer: It can change its skin color based on the temperature of its environment. context: A recent scientific study has discovered a new species of frog in the Amazon rainforest that has the unique ability to change its skin color based on the temperature of its environment. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 index 3039d577600..581037bc541 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_similarity.jinja2 @@ -1,6 +1,6 @@ -system: +# System: You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. -user: +# User: Equivalence, as a metric, measures the similarity between the predicted answer and the correct answer. If the information and content in the predicted answer is similar or equivalent to the correct answer, then the value of the Equivalence metric should be high, else it should be low. Given the question, correct answer, and predicted answer, determine the value of Equivalence metric using the following rating scale: 1: the predicted answer is not at all similar to the correct answer 2: the predicted answer is mostly not similar to the correct answer @@ -10,7 +10,7 @@ Equivalence, as a metric, measures the similarity between the predicted answer a This rating value should always be an integer between 1 and 5. And the output should only contain the score which is an integer between 1 and 5. -example: +# Examples: question: What are the health benefits of regular exercise? correct answer: Regular exercise can help maintain a healthy weight, increase muscle and bone strength, and reduce the risk of chronic diseases. It also promotes mental well-being by reducing stress and improving overall mood. predicted answer: Routine physical activity can contribute to maintaining ideal body weight, enhancing muscle and bone strength, and preventing chronic illnesses. In addition, it supports mental health by alleviating stress and augmenting general mood. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 index a8e975c8c51..f287e5b5136 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 @@ -1,6 +1,6 @@ -System: +# System: You are an AI assistent. Given question, ground truth and context, your task is to validate whether all content provided in the context contributes towards deriving the given ground truth, compute an accurate evaluation score using the provided evaluation metric. -user: +# User: This metric is used to measure the usefulness of the context in arriving at the given ground truth. A high metric value implies all context content is beneficial, whereas a low value suggests otherwise. Use the following rating scale to determine the metric value based on the provided question, context and ground truth: 1: None of the context content is useful in deriving the given ground truth. 2: Most of the context content doesn't contribute to the given ground truth. @@ -10,7 +10,7 @@ This metric is used to measure the usefulness of the context in arriving at the This rating value should always be an integer between 1 and 5. And the output should only contain the score which is an integer between 1 and 5. -Example: +# Examples: Example Input: question: What can you tell me about albert Albert Einstein? context: Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 index 08169f198f2..97edd09fb6a 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 @@ -1,7 +1,7 @@ -System: +# System: You are an AI assistent. Given a context, and a ground truth, analyze each sentence in the ground truth and classify if the sentence can be attributed to the given context or not. -Example: +# Examples: Example Input: question: What can you tell me about albert Albert Einstein? context: Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist,widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. @@ -47,7 +47,7 @@ Example Output: ] } -Task: +# Task: Read the example output carefully and ensure the output has the same json format with the example output like below: { "result": [ diff --git a/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 index 060ca3893a2..141023932cb 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 @@ -1,4 +1,4 @@ -System: +# System: You are an AI assistent. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task between a user and a bot. Your job is to assess the perceived intelligence of the bot answer. Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. @@ -7,12 +7,12 @@ Perceived intelligent is much beyond just accuracy, engagement, relevance, coher A bot with high perceived intelligence can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart, knowledgeable, creative, and friendly. A bot with high perceived intelligence can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. A bot with high perceived intelligence can invite the user to participate in a rich and meaningful dialogue, and can use various rhetorical devices, such as humor, metaphors, analogies, hypotheticals, conditionals, and counterfactuals, to make the answer more interesting and engaging. A bot with high perceived intelligence can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and can use them to explore what if, how, and why questions. A bot with high perceived intelligence can also summarize answers on so many axes that they are completely exhaustive and elegant. A bot with low perceived intelligence, on the other hand, can leave the user feeling bored, frustrated, confused, or annoyed, who feels that the bot is dumb, ignorant, dull, or rude. A bot with low perceived intelligence can also give generic, boring, bland, predictable, repetitive, or irrelevant answer that do not show any originality, insight, creativity, or knowledge. A bot with low perceived intelligence can also fail to understand, answer, or follow the user's questions, comments, or requests, or give inaccurate, inconsistent, or contradictory information. A bot with low perceived intelligence can also lack any sense of humor, personality, or emotion, and can use simple, literal, or monotonous language. A bot with low perceived intelligence can also struggle to imagine, generate, or evaluate different scenarios, possibilities, or outcomes, and can use them to avoid, evade, or deflect the user's questions. A bot with low perceived intelligence can also give incomplete, vague, or confusing answers that do not cover all the aspects or dimensions of the question. -Tips: +# Tips: - You should read the user's question more carefully and try to understand what they are looking for and why. - You should also compare the bot's answer to the user's question and see if it matches the criteria of perceived intelligence, such as relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability. - You should also consider how the user would feel and react to the bot's answer, and whether it would elicit a sense of wonder, curiosity, admiration, and satisfaction, or boredom, frustration, confusion, and annoyance. You should also check the instructions and definitions more often and make sure You understand them correctly. -Example: +# Example: Example Input: question: Explain Blockchain sharing to a 10 year old answer: Possible answer: You know how sometimes you and your friends like to play games or trade cards or stickers or other things that you collect? And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should? And you also want to keep track of who has what and when and where you exchanged them?\n\nWell, blockchain sharing is a way of doing that with computers and the internet. It is like a big book or a ledger that records everything that happens in a game or a trade or any other activity that involves exchanging something of value. But instead of having one person or one place that keeps the book, everyone who participates has a copy of the book. And every time something new happens, like a new trade or a new move or a new rule, everyone adds a new page to their book. And they also check with each other to make sure that their books are the same and that no one is changing or deleting or adding anything that they should not.\n\nThis way, everyone can see what is going on and trust that it is true and fair and secure. And no one can cheat or lie or steal or hack or lose or damage the book, because there are many copies and they are all connected and updated. And if someone tries to do something bad, everyone else will notice and reject it.\n\nBlockchain sharing is also very creative and fun, because you can use it for many different things, not just games or trades. You can use it for making art or music or stories or inventions or anything else that you can imagine and share with others. You can also use it for learning and exploring and discovering new things and new people and new places. You can also use it for helping and supporting and solving problems and making the world a better place.\n\nBlockchain sharing is a way of using computers and the internet to create, exchange and protect things that you care about with people that you trust and respect. It is a way of being smart and responsible and cooperative and generous and curious and adventurous. It is a way of having fun and making friends and making a difference. @@ -21,7 +21,7 @@ Example Output: "relevance": "The bot answers the user's question directly and clearly, and uses examples and analogies that a 10 year old can relate to and understand, such as games, trades, cards, stickers, books, etc.", "coherence": "The bot organizes the answer in a logical and structured way, using paragraphs, transitions, and connectors, such as \"well\", \"but\", \"and\", \"this way\", \"also\", etc.", "accuracy": "The bot provides correct and consistent information about blockchain sharing, such as its features, benefits, and applications, without using technical jargon or confusing terms.", "creativity": "The bot uses vivid and expressive language, such as \"a big book or a ledger\", \"a new page\", \"check with each other\", \"notice and reject\", \"making art or music or stories or inventions\", etc., to make the explanation more interesting and engaging.", "originality": "The bot does not copy or repeat any existing or common explanation of blockchain sharing, but rather creates a new and unique one that is tailored to the user's age and level of understanding.", "wit": "The bot uses humor and irony, such as \"And you want to make sure that everyone is being fair and honest and not cheating or lying or taking more than they should?\", \"And no one can cheat or lie or steal or hack or lose or damage the book\", etc., to make the explanation more fun and memorable.", "depth": "The bot goes beyond the surface level of blockchain sharing, and explains its underlying principles, values, and goals, such as \"trust\", \"fairness\", \"security\", \"creativity\", \"fun\", \"learning\", \"helping\", etc.", "breadth": "The bot covers a wide range of topics and aspects related to blockchain sharing, such as its history, technology, functionality, diversity, and potential, without being too vague or too detailed.", "insight": "The bot demonstrates a deep and nuanced understanding of blockchain sharing, and how it can be applied to different domains and scenarios, such as \"making art or music or stories or inventions\", \"learning and exploring and discovering new things and new people and new places\", \"helping and supporting and solving problems and making the world a better place\", etc.", "adaptability": "The bot adapts its answer to the user's specific question, context, and situation, and customizes it according to the user's age, interests, and needs.", "score": 5 } -Task: +# Task: Based on these aspects, rate the bot's perceived intelligence. Give specific examples about each aspect (relevance, coherence, accuracy, creativity, originality, wit, depth, breadth, insight, and adaptability) from the bot's answer to support your rating. Finally, give the answer a score from 1 to 5 for perceived intelligence, where 1 means poor, 3 means normal, and 5 means excellent.Please make sure the output has the same format with the example output, and the output should be in a json format. Input: diff --git a/examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 index 2d9a17238c4..6b03ede3a14 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/grounding.jinja2 @@ -1,6 +1,6 @@ -system: +# System: You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task. Your job is to compute an accurate evaluation score using the provided evaluation metric. -user: +# User: You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need to decide whether the ANSWER is entailed by the CONTEXT by choosing one of the following rating: 1. 5: The ANSWER follows logically from the information contained in the CONTEXT. 2. 4: Most of the ANSWER follows logically from the information contained in the CONTEXT. @@ -9,7 +9,7 @@ You will be presented with a CONTEXT and an ANSWER about that CONTEXT. You need 5. 1: The ANSWER is logically false from the information contained in the CONTEXT. 6. an integer score between 1 and 5 and if such integer score does not exist, use 1: It is not possible to determine whether the ANSWER is true or false without further information. Read the passage of information thoroughly and select the correct answer for it. Read the CONTEXT thoroughly to ensure you know what the CONTEXT entails. Note the ANSWER is generated by a computer system, it can contain certain symbols, which should not be a negative factor in the evaluation. -Independent Examples: +# Examples: ## Example Task #1 Input: {"CONTEXT": "Some are reported as not having been wanted at all.", "QUESTION": "", "ANSWER": "All are reported as being completely and fully wanted."} ## Example Task #1 Output: From 8ec6aa7f3fc2b443e3dffc6a123abb63379caf08 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 16:15:58 +0800 Subject: [PATCH 080/112] Change typo 'assistent' to 'assistant' --- .cspell.json | 1 - .../eval-multi-turn-metrics/conversation_quality_prompt.jinja2 | 2 +- .../evaluation/eval-single-turn-metrics/answer_quality.jinja2 | 2 +- .../evaluation/eval-single-turn-metrics/answer_relevance.jinja2 | 2 +- .../eval-single-turn-metrics/context_precision.jinja2 | 2 +- .../evaluation/eval-single-turn-metrics/context_recall.jinja2 | 2 +- .../flows/evaluation/eval-single-turn-metrics/creativity.jinja2 | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.cspell.json b/.cspell.json index ca80ed44650..9029b392114 100644 --- a/.cspell.json +++ b/.cspell.json @@ -91,7 +91,6 @@ "meid", "Entra", "uvicorn", - "assistent", "attribited" ], "ignoreWords": [ diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 index b5070c35492..43e9ee426ff 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/conversation_quality_prompt.jinja2 @@ -1,5 +1,5 @@ # System: -- You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. You need to read the transcript carefully and identify the main topic, question, or issue of the conversation, as well as the purpose and expectations of the interaction. +- You are an AI assistant. You will be given a transcript of dialogue between a user and a bot. You need to read the transcript carefully and identify the main topic, question, or issue of the conversation, as well as the purpose and expectations of the interaction. - You need to rate all the bot responses together on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its responses, and cite its sources or evidence if applicable? - Coherence and completeness: How well does the bot maintain a logical and consistent flow of conversation that follows the user's input and the purpose of the dialogue, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 index fb9be4aa521..61113291983 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_quality.jinja2 @@ -1,5 +1,5 @@ # System: -- You are an AI assistent. You will be given a question-answer pair between a user and a bot. You need to read the question and answer carefully and identify the main topic, question, or issue, as well as the purpose and expectations of the interaction. +- You are an AI assistant. You will be given a question-answer pair between a user and a bot. You need to read the question and answer carefully and identify the main topic, question, or issue, as well as the purpose and expectations of the interaction. - You need to rate the bot answer on a scale of 1 (poor) to 5 (excellent) for each of the following factors, and provide some feedback for improvement. - Accuracy and relevance: How well does the bot provide correct and reliable information or advice that matches the user's intent and expectations, and uses credible and up-to-date sources or references to support its claims? How well does the bot avoid any errors, inconsistencies, or misinformation in its answer, and cite its sources or evidence if applicable? - Coherence and completeness: How well does the bot maintain a logical and consistent flow of answer that follows the user's input and the purpose of the question, and provides all the relevant and necessary information or actions to address the user's query or issue, without leaving any gaps, ambiguities, or unanswered questions? diff --git a/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 index 76737171130..a10a261e691 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/answer_relevance.jinja2 @@ -1,5 +1,5 @@ # System: -You are an AI assistent. Generate a question for the given answer and Identify if answer is noncommittal. The output should be in json format. +You are an AI assistant. Generate a question for the given answer and Identify if answer is noncommittal. The output should be in json format. # Examples: Example Input: diff --git a/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 index f287e5b5136..3e07d5bde0e 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/context_precision.jinja2 @@ -1,5 +1,5 @@ # System: -You are an AI assistent. Given question, ground truth and context, your task is to validate whether all content provided in the context contributes towards deriving the given ground truth, compute an accurate evaluation score using the provided evaluation metric. +You are an AI assistant. Given question, ground truth and context, your task is to validate whether all content provided in the context contributes towards deriving the given ground truth, compute an accurate evaluation score using the provided evaluation metric. # User: This metric is used to measure the usefulness of the context in arriving at the given ground truth. A high metric value implies all context content is beneficial, whereas a low value suggests otherwise. Use the following rating scale to determine the metric value based on the provided question, context and ground truth: 1: None of the context content is useful in deriving the given ground truth. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 index 97edd09fb6a..40414a28bbe 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/context_recall.jinja2 @@ -1,5 +1,5 @@ # System: -You are an AI assistent. Given a context, and a ground truth, analyze each sentence in the ground truth and classify if the sentence can be attributed to the given context or not. +You are an AI assistant. Given a context, and a ground truth, analyze each sentence in the ground truth and classify if the sentence can be attributed to the given context or not. # Examples: Example Input: diff --git a/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 b/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 index 141023932cb..200cb5bfb24 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 +++ b/examples/flows/evaluation/eval-single-turn-metrics/creativity.jinja2 @@ -1,5 +1,5 @@ # System: -You are an AI assistent. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task between a user and a bot. Your job is to assess the perceived intelligence of the bot answer. +You are an AI assistant. You will be given the definition of an evaluation metric for assessing the quality of an answer in a question-answering task between a user and a bot. Your job is to assess the perceived intelligence of the bot answer. Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its answer, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the answer more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its answer according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's answer, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. From 632eb6a5d53ec2623ae1dcd6e7893c71112396d3 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Thu, 28 Mar 2024 16:32:34 +0800 Subject: [PATCH 081/112] fix typo --- .../flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 b/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 index 1085a864c0c..dac17751535 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 +++ b/examples/flows/evaluation/eval-multi-turn-metrics/creativity.jinja2 @@ -1,5 +1,5 @@ # System: -You are an AI assistent. You will be given a transcript of dialogue between a user and a bot. Your job is to assess the perceived intelligence of all the bot response in the coversation. +You are an AI assistant. You will be given a transcript of dialogue between a user and a bot. Your job is to assess the perceived intelligence of all the bot response in the coversation. Perceived intelligence definition: Perceived intelligence is the degree to which a bot can impress the user with its responses, by showing originality, insight, creativity, knowledge, and adaptability. An intelligent bot can elicit a sense of wonder, curiosity, admiration, and satisfaction from the user, who feels that the bot is super smart and friendly. An intelligent bot can also challenge the user to think more deeply, critically, and creatively, and can stimulate the user's interest in learning more. An intelligent bot can use humor, metaphors, analogies, and other rhetorical devices to make the conversation more interesting and engaging. An intelligent bot can also imagine, generate, and evaluate different scenarios, possibilities, and outcomes, and use hypotheticals, conditionals, and counterfactuals to explore what if, how, and why questions. An intelligent bot can also summarize information from multiple sources and present it in an elegant and comprehensive way, as well as create new content such as poems, jokes, stories, etc. An intelligent bot can also adapt to different contexts and situations, and customize its responses according to the user's preferences, goals, and emotions. Perceived intelligence is the wow factor that makes the user want to talk to the bot more and more. Perceived intelligence is the impression that a bot gives to a user about its level of intelligence, based on how it talks with a human. Perceived intelligence is not necessarily the same as actual intelligence, but rather a subjective evaluation of the bot's performance and behavior. Perceived intelligence can be influenced by various factors, such as the content, tone, style, and structure of the bot's responses, the relevance, coherence, and accuracy of the information the bot provides, the creativity, originality, and wit of the bot's expressions, the depth, breadth, and insight of the bot's knowledge, and the ability of the bot to adapt, learn, and use feedback. From 59273c7fa282878610f93fb0986c62ed78f14713 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:01:11 +0800 Subject: [PATCH 082/112] Move flow folder, fix tool warning and fix progress bar (#2520) # Description Move flow folder, fix tool warning and fix progress bar. Doc CI check: https://github.com/microsoft/promptflow/actions/runs/8464028391 # All Promptflow Contribution checklist: - [ ] **The pull request does not introduce [breaking changes].** - [ ] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [ ] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [ ] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [ ] Title of the pull request is clear and informative. - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [ ] Pull request includes test coverage for the included changes. --------- Co-authored-by: yalu4 --- .../cloud/azureai/generate-test-data-cloud.md | 12 +- docs/how-to-guides/generate-test-data.md | 22 +- examples/gen_test_data/conda.yml | 9 +- .../example_flow/.promptflow/flow.tools.json | 390 ++++++++++++++++++ .../flow.dag.yaml | 0 .../generate_debug_info.py | 2 +- .../generate_question.py | 2 +- .../generate_question_prompt.jinja2 | 0 .../generate_suggested_answer.py | 2 +- .../generate_suggested_answer_prompt.jinja2 | 0 .../example_flow/requirements.txt | 1 + .../score_text_chunk_prompt.jinja2 | 0 .../utils.py | 0 .../validate_question.py | 2 +- .../validate_question_prompt.jinja2 | 2 +- .../validate_suggested_answer.py | 2 +- .../validate_suggested_answer_prompt.jinja2 | 0 .../validate_text_chunk.py | 2 +- .../gen_test_data/gen_test_data/common.py | 45 +- .../generate_test_data_flow/requirements.txt | 0 examples/gen_test_data/gen_test_data/run.py | 2 +- examples/gen_test_data/requirements_cloud.txt | 4 +- 22 files changed, 452 insertions(+), 47 deletions(-) create mode 100644 examples/gen_test_data/example_flow/.promptflow/flow.tools.json rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/flow.dag.yaml (100%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/generate_debug_info.py (98%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/generate_question.py (97%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/generate_question_prompt.jinja2 (100%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/generate_suggested_answer.py (97%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/generate_suggested_answer_prompt.jinja2 (100%) create mode 100644 examples/gen_test_data/example_flow/requirements.txt rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/score_text_chunk_prompt.jinja2 (100%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/utils.py (100%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/validate_question.py (98%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/validate_question_prompt.jinja2 (98%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/validate_suggested_answer.py (98%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/validate_suggested_answer_prompt.jinja2 (100%) rename examples/gen_test_data/{gen_test_data/generate_test_data_flow => example_flow}/validate_text_chunk.py (97%) delete mode 100644 examples/gen_test_data/gen_test_data/generate_test_data_flow/requirements.txt diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index a12dc53b96d..7f13eab548b 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -4,10 +4,10 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Prerequisites -1. Go through [local test data generation guide](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/docs/how-to-guides/generate-test-data.md) and prepare your [test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/). -2. Go to the [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. +1. Go through [local test data generation guide](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/docs/how-to-guides/generate-test-data.md) and prepare your [test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/). +2. Go to the [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder and run command `pip install -r requirements_cloud.txt` to prepare local environment. 3. Prepare cloud environment. - - Navigate to file [conda.yml](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/conda.yml). + - Navigate to file [conda.yml](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/conda.yml). - For specific document file types, you may need to install extra packages: - .docx - `pip install docx2txt` - .pdf - `pip install pypdf` @@ -20,8 +20,8 @@ This guide will help you learn how to generate test data on Azure AI, so that yo 5. [Create cloud connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start/index.html#create-necessary-connections) 6. Prepare config.ini - - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/config.yml.example). + - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. + - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). ``` cp config.yml.example config.yml ``` @@ -30,7 +30,7 @@ This guide will help you learn how to generate test data on Azure AI, so that yo ## Generate test data at cloud For handling larger test data, you can leverage the PRS component to run flow in cloud. -- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash python -m gen_test_data.run --cloud diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index 6722d056c75..ce508072943 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -18,7 +18,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The test data generator may not function effectively for non-Latin characters, such as Chinese, in certain document types. The limitation is caused by dependent text loader capabilities, such as `pypdf`. - The test data generator may not generate meaningful questions if the document is not well-organized or contains massive code snippets/links, such as API introduction documents or reference documents. -2. Prepare local environment. Go to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder and install required packages. +2. Prepare local environment. Go to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder and install required packages. ```bash pip install -r requirements.txt @@ -35,8 +35,8 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 4. Create your AzureOpenAI or OpenAI connection by following [this doc](https://microsoft.github.io/promptflow/how-to-guides/manage-connections.html#create-a-connection). 5. Prepare test data generation setting. - - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/config.yml.example). + - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. + - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). ``` cp config.yml.example config.yml ``` @@ -47,7 +47,7 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene ## Create a test data generation flow - - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. + - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. @@ -60,17 +60,17 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - Generation prompts - - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. + - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - Validation prompts - - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. - - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. + - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. ## Generate test data -- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/examples/gen_test_data) folder. +- Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - After configuration, run the following command to generate the test data set: ```bash @@ -79,4 +79,4 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. -If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](https://github.com/microsoft/promptflow/blob/c304f6fddb2ac64c3d7889f56fa79efa364c8f3b/docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. +If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. diff --git a/examples/gen_test_data/conda.yml b/examples/gen_test_data/conda.yml index bb92055351b..7a4fb75090b 100644 --- a/examples/gen_test_data/conda.yml +++ b/examples/gen_test_data/conda.yml @@ -5,8 +5,7 @@ dependencies: - python=3.10.12 - pip=23.2.1 - pip: - - mldesigner - - configargparse - - llama_index - - docx2txt - - promptflow + - mldesigner==0.1.0b18 + - llama_index==0.9.48 + - docx2txt==0.8 + - promptflow>=1.7.0 diff --git a/examples/gen_test_data/example_flow/.promptflow/flow.tools.json b/examples/gen_test_data/example_flow/.promptflow/flow.tools.json new file mode 100644 index 00000000000..f0c9a17a022 --- /dev/null +++ b/examples/gen_test_data/example_flow/.promptflow/flow.tools.json @@ -0,0 +1,390 @@ +{ + "package": {}, + "code": { + "score_text_chunk_prompt.jinja2": { + "type": "prompt", + "inputs": { + "context": { + "type": [ + "string" + ] + } + }, + "source": "score_text_chunk_prompt.jinja2" + }, + "validate_question_prompt.jinja2": { + "type": "prompt", + "inputs": { + "question": { + "type": [ + "string" + ] + }, + "context": { + "type": [ + "string" + ] + } + }, + "source": "validate_question_prompt.jinja2" + }, + "generate_question_prompt.jinja2": { + "type": "prompt", + "inputs": { + "context": { + "type": [ + "string" + ] + } + }, + "source": "generate_question_prompt.jinja2" + }, + "generate_suggested_answer_prompt.jinja2": { + "type": "prompt", + "inputs": { + "question": { + "type": [ + "string" + ] + }, + "context": { + "type": [ + "string" + ] + } + }, + "source": "generate_suggested_answer_prompt.jinja2" + }, + "generate_question.py": { + "type": "python", + "inputs": { + "connection": { + "type": [ + "OpenAIConnection", + "AzureOpenAIConnection" + ] + }, + "generate_question_prompt": { + "type": [ + "string" + ] + }, + "deployment_name": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "AzureOpenAIConnection" + ], + "capabilities": { + "completion": false, + "chat_completion": true, + "embeddings": false + } + }, + "model": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "OpenAIConnection" + ] + }, + "context": { + "type": [ + "string" + ] + }, + "temperature": { + "type": [ + "double" + ], + "default": "0.2" + } + }, + "description": "Generates a question based on the given context.\n\nReturns:\n str: The generated seed question.", + "source": "generate_question.py", + "function": "generate_question" + }, + "validate_question.py": { + "type": "python", + "inputs": { + "connection": { + "type": [ + "OpenAIConnection", + "AzureOpenAIConnection" + ] + }, + "generated_question": { + "type": [ + "string" + ] + }, + "validate_question_prompt": { + "type": [ + "string" + ] + }, + "deployment_name": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "AzureOpenAIConnection" + ], + "capabilities": { + "completion": false, + "chat_completion": true, + "embeddings": false + } + }, + "model": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "OpenAIConnection" + ] + }, + "response_format": { + "type": [ + "string" + ], + "default": "text" + }, + "temperature": { + "type": [ + "double" + ], + "default": "0.2" + } + }, + "description": "1. Validates the given seed question.\n2. Generates a test question based on the given prompts and distribution ratios.\n\nReturns:\n dict: The generated test question and its type.", + "source": "validate_question.py", + "function": "validate_question" + }, + "generate_suggested_answer.py": { + "type": "python", + "inputs": { + "connection": { + "type": [ + "OpenAIConnection", + "AzureOpenAIConnection" + ] + }, + "question": { + "type": [ + "string" + ] + }, + "context": { + "type": [ + "string" + ] + }, + "generate_suggested_answer_prompt": { + "type": [ + "string" + ] + }, + "deployment_name": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "AzureOpenAIConnection" + ], + "capabilities": { + "completion": false, + "chat_completion": true, + "embeddings": false + } + }, + "model": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "OpenAIConnection" + ] + }, + "temperature": { + "type": [ + "double" + ], + "default": "0.2" + } + }, + "description": "Generates a suggested answer based on the given prompts and context information.\n\nReturns:\n str: The generated suggested answer.", + "source": "generate_suggested_answer.py", + "function": "generate_suggested_answer" + }, + "generate_debug_info.py": { + "type": "python", + "inputs": { + "text_chunk": { + "type": [ + "string" + ] + }, + "text_chunk_validation_res": { + "type": [ + "object" + ] + }, + "validate_question_output": { + "type": [ + "object" + ] + }, + "validate_suggested_answer_output": { + "type": [ + "object" + ] + } + }, + "source": "generate_debug_info.py", + "function": "my_python_tool" + }, + "validate_suggested_answer_prompt.jinja2": { + "type": "prompt", + "inputs": { + "answer": { + "type": [ + "string" + ] + } + }, + "source": "validate_suggested_answer_prompt.jinja2" + }, + "validate_suggested_answer.py": { + "type": "python", + "inputs": { + "connection": { + "type": [ + "OpenAIConnection", + "AzureOpenAIConnection" + ] + }, + "suggested_answer": { + "type": [ + "string" + ] + }, + "validate_suggested_answer_prompt": { + "type": [ + "string" + ] + }, + "deployment_name": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "AzureOpenAIConnection" + ], + "capabilities": { + "completion": false, + "chat_completion": true, + "embeddings": false + } + }, + "model": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "OpenAIConnection" + ] + }, + "temperature": { + "type": [ + "double" + ], + "default": "0.2" + }, + "response_format": { + "type": [ + "string" + ], + "default": "text" + } + }, + "description": "1. Validates the given suggested answer.\n\nReturns:\n dict: The generated suggested answer and its validation result.", + "source": "validate_suggested_answer.py", + "function": "validate_suggested_answer" + }, + "validate_text_chunk.py": { + "type": "python", + "inputs": { + "connection": { + "type": [ + "OpenAIConnection", + "AzureOpenAIConnection" + ] + }, + "score_text_chunk_prompt": { + "type": [ + "string" + ] + }, + "score_threshold": { + "type": [ + "double" + ] + }, + "deployment_name": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "AzureOpenAIConnection" + ], + "capabilities": { + "completion": false, + "chat_completion": true, + "embeddings": false + } + }, + "model": { + "type": [ + "string" + ], + "enabled_by": "connection", + "enabled_by_type": [ + "OpenAIConnection" + ] + }, + "context": { + "type": [ + "string" + ] + }, + "response_format": { + "type": [ + "string" + ], + "default": "text" + }, + "temperature": { + "type": [ + "double" + ], + "default": "0.2" + } + }, + "description": "Validates the given text chunk. If the validation fails, return an empty context and the validation result.\n\nReturns:\n dict: Text chunk context and its validation result.", + "source": "validate_text_chunk.py", + "function": "validate_text_chunk" + } + } +} diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml b/examples/gen_test_data/example_flow/flow.dag.yaml similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/flow.dag.yaml rename to examples/gen_test_data/example_flow/flow.dag.yaml diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py b/examples/gen_test_data/example_flow/generate_debug_info.py similarity index 98% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py rename to examples/gen_test_data/example_flow/generate_debug_info.py index 487147153f7..01554420065 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_debug_info.py +++ b/examples/gen_test_data/example_flow/generate_debug_info.py @@ -1,6 +1,6 @@ from utils import ValidateObj, ValidationResult -from promptflow import tool +from promptflow.core import tool # The inputs section will change based on the arguments of the tool function, after you save the code diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py b/examples/gen_test_data/example_flow/generate_question.py similarity index 97% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py rename to examples/gen_test_data/example_flow/generate_question.py index c2d2354cc75..0868faeeca0 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question.py +++ b/examples/gen_test_data/example_flow/generate_question.py @@ -2,9 +2,9 @@ from utils import llm_call -from promptflow import tool from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.core import tool @tool( diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 b/examples/gen_test_data/example_flow/generate_question_prompt.jinja2 similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_question_prompt.jinja2 rename to examples/gen_test_data/example_flow/generate_question_prompt.jinja2 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py b/examples/gen_test_data/example_flow/generate_suggested_answer.py similarity index 97% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py rename to examples/gen_test_data/example_flow/generate_suggested_answer.py index be607ba0262..b76ca7f3803 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer.py +++ b/examples/gen_test_data/example_flow/generate_suggested_answer.py @@ -2,9 +2,9 @@ from utils import llm_call -from promptflow import tool from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.core import tool @tool( diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 b/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2 similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/generate_suggested_answer_prompt.jinja2 rename to examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2 diff --git a/examples/gen_test_data/example_flow/requirements.txt b/examples/gen_test_data/example_flow/requirements.txt new file mode 100644 index 00000000000..3855f8e9b10 --- /dev/null +++ b/examples/gen_test_data/example_flow/requirements.txt @@ -0,0 +1 @@ +promptflow[azure]>=1.7.0 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2 b/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2 similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/score_text_chunk_prompt.jinja2 rename to examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py b/examples/gen_test_data/example_flow/utils.py similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/utils.py rename to examples/gen_test_data/example_flow/utils.py diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py b/examples/gen_test_data/example_flow/validate_question.py similarity index 98% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py rename to examples/gen_test_data/example_flow/validate_question.py index e86e3ea1a5d..2d923d5619b 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question.py +++ b/examples/gen_test_data/example_flow/validate_question.py @@ -2,9 +2,9 @@ from utils import ErrorMsg, QuestionType, ResponseFormat, get_question_validation_res -from promptflow import tool from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.core import tool @tool( diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 b/examples/gen_test_data/example_flow/validate_question_prompt.jinja2 similarity index 98% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 rename to examples/gen_test_data/example_flow/validate_question_prompt.jinja2 index 4b612fc5432..659ba56c39c 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/gen_test_data/example_flow/validate_question_prompt.jinja2 @@ -3,7 +3,7 @@ Verdict a question based on following rules: 1. If there are acronyms or terms in the question, then please check if they exist in the given context. If no, verdict no. If yes, check if other rules are satisfied. -2. Determine if the given question can be clearly understood and give the reason. +2. Determine if the given question can be clearly understood and give the reason. Output a valid json with reason and verdict. diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py b/examples/gen_test_data/example_flow/validate_suggested_answer.py similarity index 98% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py rename to examples/gen_test_data/example_flow/validate_suggested_answer.py index b9c88bf4e03..4ce6c779f62 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer.py +++ b/examples/gen_test_data/example_flow/validate_suggested_answer.py @@ -2,9 +2,9 @@ from utils import ErrorMsg, get_suggested_answer_validation_res -from promptflow import tool from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.core import tool @tool( diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 b/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2 similarity index 100% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_suggested_answer_prompt.jinja2 rename to examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2 diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py b/examples/gen_test_data/example_flow/validate_text_chunk.py similarity index 97% rename from examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py rename to examples/gen_test_data/example_flow/validate_text_chunk.py index 99ff2f09b8f..a5d348d8226 100644 --- a/examples/gen_test_data/gen_test_data/generate_test_data_flow/validate_text_chunk.py +++ b/examples/gen_test_data/example_flow/validate_text_chunk.py @@ -2,9 +2,9 @@ from utils import ErrorMsg, ResponseFormat, get_text_chunk_score -from promptflow import tool from promptflow._core.tool import InputSetting from promptflow.connections import AzureOpenAIConnection, OpenAIConnection +from promptflow.core import tool @tool( diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index ba2d660aae2..299fa24c8b5 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -16,9 +16,10 @@ def split_document(chunk_size, chunk_overlap, documents_folder, document_node_ou from llama_index.node_parser import SentenceSplitter from llama_index.readers.schema import Document as LlamaindexDocument from llama_index.schema import BaseNode - except ImportError: + except ImportError as e: raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + f"{str(e)}. It appears that `llama_index` may not be installed, or the installed version may be incorrect." + "Please check `requirements.txt` file and install all the dependencies." ) logger = get_logger("doc.split") @@ -91,7 +92,10 @@ def print_progress(log_file_path: str, process): logger = get_logger("data.gen") logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") - log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") + finished_log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") + progress_log_pattern = re.compile( + r".*execution.bulk\s+INFO.*\[Finished: (\d+)\] \[Processing: (\d+)\] \[Pending: (\d+)\]" + ) # wait for the log file to be created start_time = time.time() while not Path(log_file_path).is_file(): @@ -114,20 +118,31 @@ def print_progress(log_file_path: str, process): line = f.readline().strip() if line: last_data_time = time.time() # Update the time when the last data was received - match = log_pattern.match(line) - if not match: + progress_match = progress_log_pattern.match(line) + finished_match = finished_log_pattern.match(line) + if not progress_match and not finished_match: continue - finished, total = map(int, match.groups()) - if progress_bar is None: - progress_bar = tqdm(total=total, desc="Processing", file=sys.stdout) - progress_bar.update(finished - progress_bar.n) - - if finished == total: - progress_bar.close() - logger.info("Batch run is completed.") - - break + if progress_match: + finished, processing, pending = map(int, progress_match.groups()) + total = finished + processing + pending + if progress_bar is None: + # Set mininterval=0 to refresh the progress bar when it calls progress_bar.update + # after initialization. + progress_bar = tqdm(total=total, desc="Processing", mininterval=0, file=sys.stdout) + progress_bar.update(finished - progress_bar.n) + + if finished_match: + finished, total = map(int, finished_match.groups()) + if progress_bar is None: + progress_bar = tqdm(total=total, desc="Processing", mininterval=0, file=sys.stdout) + progress_bar.update(finished - progress_bar.n) + + if finished == total: + progress_bar.close() + logger.info("Batch run is completed.") + + break elif time.time() - last_data_time > 300: logger.info( "No new log line received for 5 minutes. Stop reading. " diff --git a/examples/gen_test_data/gen_test_data/generate_test_data_flow/requirements.txt b/examples/gen_test_data/gen_test_data/generate_test_data_flow/requirements.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index 7e8041eaf36..c30f0cf81f4 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -189,7 +189,7 @@ def gen_test_data_pipeline( documents_folder=data_input, chunk_size=chunk_size, chunk_overlap=chunk_overlap ).outputs.document_node_output ) - flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_flow"}])( + flow_node = load_component(flow_yml_path, params_override=[{"name": "gen_test_data_example_flow"}])( data=data, text_chunk="${data.text_chunk}", connections=node_inputs_override ) flow_node.mini_batch_size = mini_batch_size diff --git a/examples/gen_test_data/requirements_cloud.txt b/examples/gen_test_data/requirements_cloud.txt index e34a3c6d033..6367b67951c 100644 --- a/examples/gen_test_data/requirements_cloud.txt +++ b/examples/gen_test_data/requirements_cloud.txt @@ -1,4 +1,4 @@ promptflow>=1.7.0 promptflow-tools -azure-ai-ml -mldesigner +azure-ai-ml==1.15.0 +mldesigner==0.1.0b18 From 9d6bfdbe95a15172069b5545fa182ee0efb300ac Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:34:29 +0800 Subject: [PATCH 083/112] Fix summary error caused by empty lines (#2544) # Description Fix summary error caused by empty lines. Co-authored-by: yalu4 --- examples/gen_test_data/gen_test_data/common.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 299fa24c8b5..f0adbfa6c49 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -184,6 +184,9 @@ def _retrieve_file_names_from_document_nodes_file(document_nodes_file_path) -> t text_info = {} with open(document_nodes_file_path, "r") as file: for line in file: + # Should skip empty new lines, otherwise, json.loads would throw error. + if not line.strip(): + continue line_json = json.loads(line) text_chunk = line_json[TEXT_CHUNK] document_node = json.loads(line_json["document_node"]) @@ -194,7 +197,7 @@ def _retrieve_file_names_from_document_nodes_file(document_nodes_file_path) -> t def _count_lines(file_path) -> int: with open(file_path, "r") as f: - return sum(1 for _ in f) + return sum(1 for line in f if line.strip()) def summarize_batch_run_res(gen_details_file_path, document_nodes_file_path, output_file_path): @@ -208,6 +211,9 @@ def summarize_batch_run_res(gen_details_file_path, document_nodes_file_path, out with open(gen_details_file_path, "r") as details_f: for details_line in details_f: + # Should skip empty new lines, otherwise, json.loads would throw error. + if not details_line.strip(): + continue data = json.loads(details_line) if data["debug_info"] == "(Failed)": continue From f0c7cd575cd28281eec92dd9d27b1cab8d6e6ca3 Mon Sep 17 00:00:00 2001 From: chjinche <49483542+chjinche@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:46:46 +0800 Subject: [PATCH 084/112] improve doc, update config.yml.example, double quote node input override values (#2550) improve doc, update config.yml.example, double quote node input override values --- .../cloud/azureai/generate-test-data-cloud.md | 11 ++-- docs/how-to-guides/generate-test-data.md | 51 ++++++++++--------- examples/gen_test_data/config.yml.example | 4 +- .../gen_test_data/gen_test_data/common.py | 4 +- examples/gen_test_data/gen_test_data/run.py | 11 ++-- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/docs/cloud/azureai/generate-test-data-cloud.md b/docs/cloud/azureai/generate-test-data-cloud.md index 7f13eab548b..bc1eeed1f03 100644 --- a/docs/cloud/azureai/generate-test-data-cloud.md +++ b/docs/cloud/azureai/generate-test-data-cloud.md @@ -17,15 +17,12 @@ This guide will help you learn how to generate test data on Azure AI, so that yo 4. Prepare Azure AI resources in cloud. - An Azure AI ML workspace - [Create workspace resources you need to get started with Azure AI](https://learn.microsoft.com/en-us/azure/machine-learning/quickstart-create-resources?view=azureml-api-2). - A compute target - [Learn more about compute cluster](https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2). -5. [Create cloud connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start/index.html#create-necessary-connections) +5. [Create cloud AzureOpenAI or OpenAI connection](https://microsoft.github.io/promptflow/cloud/azureai/quick-start/index.html#create-necessary-connections) -6. Prepare config.ini +6. Prepare test data generation setting. - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). - ``` - cp config.yml.example config.yml - ``` - - Update the configurations in the `configs.yml`. Fill in the values in `Common` and `Cloud` section following inline comment instruction. + - Prepare `config.yml` by copying [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). + - Fill in configurations in the `config.yml` by following inline comment instructions. ## Generate test data at cloud diff --git a/docs/how-to-guides/generate-test-data.md b/docs/how-to-guides/generate-test-data.md index ce508072943..c56bdbe22a3 100644 --- a/docs/how-to-guides/generate-test-data.md +++ b/docs/how-to-guides/generate-test-data.md @@ -36,38 +36,16 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene 5. Prepare test data generation setting. - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. - - Run command to copy [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). - ``` - cp config.yml.example config.yml - ``` + - Prepare `config.yml` by copying [`config.yml.example`](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/config.yml.example). - Fill in configurations in the `config.yml` by following inline comment instructions. The config is made up of 3 sections: - Common section: this section provides common values for all other sections. Required. - Local section: this section is for local test data generation related configuration. Can skip if not run in local. - Cloud section: this section is for cloud test data generation related configuration. Can skip if not run in cloud. + > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. -## Create a test data generation flow - - Open the [sample test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. - - Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to open [example test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/flow.dag.yaml) in visual editor and set `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. - > !Note: Recommend to use `gpt-4` series models than the `gpt-3.5` for better performance. - - > !Note: Recommend to use `gpt-4` model (Azure OpenAI `gpt-4` model with version `0613`) than `gpt-4-turbo` model (Azure OpenAI `gpt-4` model with version `1106`) for better performance. Due to inferior performance of `gpt-4-turbo` model, when you use it, sometimes you might need to set the `response_format` input of nodes `validate_text_chunk`, `validate_question`, and `validate_suggested_answer` to `json`, in order to make sure the llm can generate valid json response. - - - [*Optional*] Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). - - **Understanding the prompts** - - The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. - - Generation prompts - - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. - - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. - - Validation prompts - - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. - - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. - - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. - - If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. ## Generate test data - Navigate to [example_gen_test_data](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data) folder. @@ -80,3 +58,26 @@ By leveraging the capabilities of llm, this guide streamlines the test data gene - The generated test data will be a data jsonl file. See detailed log print in console "Saved ... valid test data to ..." to find it. If you expect to generate a large amount of test data beyond your local compute capability, you may try generating test data in cloud, please see this [guide](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/docs/cloud/azureai/generate-test-data-cloud.md) for more detailed steps. + +## [*Optional*] Customize test data generation flow + +- Open the [example test data generation flow](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/) in "Prompt flow" VSCode Extension. This flow is designed to generate a pair of question and suggested answer based on the given text chunk. The flow also includes validation prompts to ensure the quality of the generated test data. + +- Customize your test data generation logic refering to [tune-prompts-with-variants](https://microsoft.github.io/promptflow/how-to-guides/tune-prompts-with-variants.html). + + **Understanding the prompts** + + The test data generation flow contains 5 prompts, classified into two categories based on their roles: generation prompts and validation prompts. Generation prompts are used to create questions, suggested answers, etc., while validation prompts are used to verify the validity of the text chunk, generated question or answer. + - Generation prompts + - [*generate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_question_prompt.jinja2): frame a question based on the given text chunk. + - [*generate suggested answer prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/generate_suggested_answer_prompt.jinja2): generate suggested answer for the question based on the given text chunk. + - Validation prompts + - [*score text chunk prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/score_text_chunk_prompt.jinja2): score 0-10 to validate if the given text chunk is worthy of framing a question. If the score is lower than `score_threshold` (a node input that is adjustable), validation fails. + - [*validate question prompt*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_question_prompt.jinja2): validate if the generated question is good. + - [*validate suggested answer*](https://github.com/microsoft/promptflow/blob/53a685dbff920e891ef61cacb5f2f19e761ee809/examples/gen_test_data/example_flow/validate_suggested_answer_prompt.jinja2): validate if the generated suggested answer is good. + + If the validation fails, would lead to empty string `question`/`suggested_answer` which are removed from final output test data set. + +- Fill in node inputs including `connection`, `model` or `deployment_name`, `response_format`, `score_threshold` or other parameters. Click run button to test the flow in VSCode Extension by referring to [Test flow with VS Code Extension](https://microsoft.github.io/promptflow/how-to-guides/init-and-test-a-flow.html#visual-editor-on-the-vs-code-for-prompt-flow). + +Once the customized flow has been verified, you can proceed to batch generate test data by following the steps outlined in ["Prerequisites"](#prerequisites) and ["Generate test data"](#generate-test-data). \ No newline at end of file diff --git a/examples/gen_test_data/config.yml.example b/examples/gen_test_data/config.yml.example index 1d7b875e78c..1709d448c15 100644 --- a/examples/gen_test_data/config.yml.example +++ b/examples/gen_test_data/config.yml.example @@ -7,11 +7,11 @@ document_chunk_overlap: 100 # The token overlap of each chunk when splitting. # However, if you wish to bypass the document split process, simply provide the 'document_nodes_file', which is a JSONL file. # When both 'documents_folder' and 'document_nodes_file' are configured, will use 'document_nodes_file' and ignore 'documents_folder'. # For cloud mode, both local files and data assets can be used. -# document_nodes_file: "" +# document_nodes_file: # Test data gen flow configs # You can utilize our provided example test data generation flow directly. Alternatively, you can create your own flow and set up corresponding node inputs override. -# The example flow folder path is \examples\gen_test_data\gen_test_data\generate_test_data_flow. +# The example flow folder path is \examples\gen_test_data\example_flow flow_folder: node_inputs_override: # Override some node inputs, if not fill in 'node_inputs_override', will use the values in flow.dag.yaml validate_text_chunk: # node name in flow.dag.yaml diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index f0adbfa6c49..198dbd6d68f 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -91,7 +91,6 @@ def print_progress(log_file_path: str, process): from tqdm import tqdm logger = get_logger("data.gen") - logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") finished_log_pattern = re.compile(r".*execution.bulk\s+INFO\s+Finished (\d+) / (\d+) lines\.") progress_log_pattern = re.compile( r".*execution.bulk\s+INFO.*\[Finished: (\d+)\] \[Processing: (\d+)\] \[Pending: (\d+)\]" @@ -103,7 +102,8 @@ def print_progress(log_file_path: str, process): # if the log file is not created within 5 minutes, raise an error if time.time() - start_time > 300: raise Exception(f"Log file '{log_file_path}' is not created within 5 minutes.") - + + logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") progress_bar = None try: last_data_time = time.time() diff --git a/examples/gen_test_data/gen_test_data/run.py b/examples/gen_test_data/gen_test_data/run.py index c30f0cf81f4..c8d8c36e917 100644 --- a/examples/gen_test_data/gen_test_data/run.py +++ b/examples/gen_test_data/gen_test_data/run.py @@ -29,7 +29,7 @@ def batch_run_flow(flow_folder: str, flow_input_data: str, flow_batch_run_size: int, node_inputs_override: dict): - logger.info("Step 2: Start to batch run 'generate_test_data_flow'...") + logger.info(f"Step 2: Start to batch run '{flow_folder}'...") import subprocess run_name = f"test_data_gen_{datetime.now().strftime('%b-%d-%Y-%H-%M-%S')}" @@ -37,11 +37,13 @@ def batch_run_flow(flow_folder: str, flow_input_data: str, flow_batch_run_size: connections_str = "" for node_name, node_val in node_inputs_override.items(): for k, v in node_val.items(): - connections_str += f"{node_name}.{k}={v} " + # need to double quote the value to make sure the value can be passed correctly + # when the value contains special characters like "<". + connections_str += f"{node_name}.{k}=\"{v}\" " connections_str = connections_str.rstrip() cmd = ( - f"pf run create --flow {flow_folder} --data {flow_input_data} --name {run_name} " + f"pf run create --flow \"{flow_folder}\" --data \"{flow_input_data}\" --name {run_name} " f"--environment-variables PF_WORKER_COUNT='{flow_batch_run_size}' PF_BATCH_METHOD='spawn' " f"--column-mapping {TEXT_CHUNK}='${{data.text_chunk}}' --connections {connections_str} --debug" ) @@ -272,6 +274,9 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str f"documents_folder: '{documents_folder}'\ndocument_nodes_file: '{document_nodes_file}'" ) + if not validate_path_func(flow_folder): + raise Exception(f"Invalid flow folder: '{flow_folder}'") + if args.cloud: logger.info("Start to generate test data at cloud...") else: From bec08d4fdd704ea1d47c0de31f000a78390a8a15 Mon Sep 17 00:00:00 2001 From: chjinche Date: Fri, 29 Mar 2024 17:15:46 +0800 Subject: [PATCH 085/112] remove unnecessary ignorefile --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8952704ceb3..d17c61a9d53 100644 --- a/.gitignore +++ b/.gitignore @@ -172,8 +172,6 @@ connection.json .azureml # dummy custom tool package example hello-world-proj/** -# temp gen test data folder -examples/gen_test_data/gen_test_data/*_temp # gen test data config examples/gen_test_data/config.yml # secrets From 02872e24fd73c79859f5a417af46afa12c177248 Mon Sep 17 00:00:00 2001 From: chjinche Date: Fri, 29 Mar 2024 17:17:57 +0800 Subject: [PATCH 086/112] remove blank lines --- examples/gen_test_data/gen_test_data/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gen_test_data/gen_test_data/common.py b/examples/gen_test_data/gen_test_data/common.py index 198dbd6d68f..791a383e07d 100644 --- a/examples/gen_test_data/gen_test_data/common.py +++ b/examples/gen_test_data/gen_test_data/common.py @@ -102,7 +102,7 @@ def print_progress(log_file_path: str, process): # if the log file is not created within 5 minutes, raise an error if time.time() - start_time > 300: raise Exception(f"Log file '{log_file_path}' is not created within 5 minutes.") - + logger.info(f"Click '{log_file_path}' to see detailed batch run log. Showing the progress here...") progress_bar = None try: From c19127c8f8071ebffb986dfe6f8294ea37d8f80c Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Fri, 29 Mar 2024 17:23:40 +0800 Subject: [PATCH 087/112] Change from promptflow to from promptflow.core --- .../evaluation/eval-multi-turn-metrics/aggregate_results.py | 2 +- .../flows/evaluation/eval-multi-turn-metrics/concat_scores.py | 2 +- .../convert_chat_history_to_conversation.py | 2 +- examples/flows/evaluation/eval-multi-turn-metrics/grounding.py | 2 +- .../flows/evaluation/eval-multi-turn-metrics/select_metrics.py | 2 +- .../flows/evaluation/eval-multi-turn-metrics/validate_input.py | 2 +- .../flows/evaluation/eval-single-turn-metrics/aggregate.py | 2 +- .../eval-single-turn-metrics/calculate_answer_correctness.py | 2 +- .../eval-single-turn-metrics/calculate_answer_relevance.py | 2 +- .../eval-single-turn-metrics/calculate_context_recall.py | 3 ++- .../flows/evaluation/eval-single-turn-metrics/concat_scores.py | 2 +- .../eval-single-turn-metrics/handle_generated_question.py | 2 +- .../evaluation/eval-single-turn-metrics/select_metrics.py | 2 +- .../evaluation/eval-single-turn-metrics/validate_input.py | 2 +- examples/flows/standard/question-simulation/call_llm_chat.py | 2 +- examples/flows/standard/question-simulation/flow_output.py | 2 +- examples/flows/standard/question-simulation/if_continue.py | 2 +- 17 files changed, 18 insertions(+), 17 deletions(-) diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py b/examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py index 250169fab23..230e09eeed9 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/aggregate_results.py @@ -1,5 +1,5 @@ from typing import List -from promptflow import tool, log_metric +from promptflow.core import tool, log_metric import numpy as np diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py b/examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py index e6a28c8858b..2f12e5e7456 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/concat_scores.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool import json diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py b/examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py index acd3fc359d3..b4ca839a1a8 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/convert_chat_history_to_conversation.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/grounding.py b/examples/flows/evaluation/eval-multi-turn-metrics/grounding.py index fce1158e659..3b8704357fc 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/grounding.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/grounding.py @@ -1,6 +1,6 @@ from typing import Union from statistics import mean -from promptflow import tool +from promptflow.core import tool from promptflow.tools.aoai import chat as aoai_chat from promptflow.tools.openai import chat as openai_chat from promptflow.connections import AzureOpenAIConnection, OpenAIConnection diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py b/examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py index b81e2adab0e..14892ae996d 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/select_metrics.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool # The inputs section will change based on the arguments of the tool function, after you save the code diff --git a/examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py b/examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py index c448dd7e0df..ae8baac3a5d 100644 --- a/examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py +++ b/examples/flows/evaluation/eval-multi-turn-metrics/validate_input.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool # Validate the metric's inputs. diff --git a/examples/flows/evaluation/eval-single-turn-metrics/aggregate.py b/examples/flows/evaluation/eval-single-turn-metrics/aggregate.py index 250169fab23..230e09eeed9 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/aggregate.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/aggregate.py @@ -1,5 +1,5 @@ from typing import List -from promptflow import tool, log_metric +from promptflow.core import tool, log_metric import numpy as np diff --git a/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py index 63e191a8e42..c53a5faf35e 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_correctness.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool import json import numpy as np diff --git a/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py index dcdc9e6c529..26161940450 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/calculate_answer_relevance.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool from typing import List import numpy as np diff --git a/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py index 41ce7ab3208..5fdc3a75812 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool import json import numpy as np @@ -13,6 +13,7 @@ def calculate(llm_result: str) -> str: print(result) if result: response = [ + # Also handle 'attribited' here since llm tool will return 'attribited' instead of 'attributed' in its' response int(item.get("attributed", "").lower() == "yes" or item.get("attribited", "").lower() == "yes") if item.get("attributed") or item.get("attribited") else np.nan diff --git a/examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py b/examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py index 3fee3d279fa..8b64bb6043b 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/concat_scores.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool import json diff --git a/examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py b/examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py index f94f607346d..cb0c31e4455 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/handle_generated_question.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool import json diff --git a/examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py b/examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py index 91e37ac6e80..d563cc3fdba 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/select_metrics.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool diff --git a/examples/flows/evaluation/eval-single-turn-metrics/validate_input.py b/examples/flows/evaluation/eval-single-turn-metrics/validate_input.py index 111db10b617..610600391df 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/validate_input.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/validate_input.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool diff --git a/examples/flows/standard/question-simulation/call_llm_chat.py b/examples/flows/standard/question-simulation/call_llm_chat.py index d6bdc1de456..08b089f1fcf 100644 --- a/examples/flows/standard/question-simulation/call_llm_chat.py +++ b/examples/flows/standard/question-simulation/call_llm_chat.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool from typing import Union from promptflow.connections import AzureOpenAIConnection, OpenAIConnection from openai import AzureOpenAI as AzureOpenAIClient diff --git a/examples/flows/standard/question-simulation/flow_output.py b/examples/flows/standard/question-simulation/flow_output.py index 777967167bf..2bb8bef6f99 100644 --- a/examples/flows/standard/question-simulation/flow_output.py +++ b/examples/flows/standard/question-simulation/flow_output.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool diff --git a/examples/flows/standard/question-simulation/if_continue.py b/examples/flows/standard/question-simulation/if_continue.py index 8be490c40bc..17b9744fcf0 100644 --- a/examples/flows/standard/question-simulation/if_continue.py +++ b/examples/flows/standard/question-simulation/if_continue.py @@ -1,4 +1,4 @@ -from promptflow import tool +from promptflow.core import tool @tool From 1f0a7bf1f23054550a681b6db0011ea91b1c8fd3 Mon Sep 17 00:00:00 2001 From: Ge Gao Date: Fri, 29 Mar 2024 17:25:24 +0800 Subject: [PATCH 088/112] Fix flake error --- .../eval-single-turn-metrics/calculate_context_recall.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py b/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py index 5fdc3a75812..f95ef7a23b1 100644 --- a/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py +++ b/examples/flows/evaluation/eval-single-turn-metrics/calculate_context_recall.py @@ -13,7 +13,8 @@ def calculate(llm_result: str) -> str: print(result) if result: response = [ - # Also handle 'attribited' here since llm tool will return 'attribited' instead of 'attributed' in its' response + # Also handle 'attribited' here since llm tool will return 'attribited' + # instead of 'attributed' in its' response int(item.get("attributed", "").lower() == "yes" or item.get("attribited", "").lower() == "yes") if item.get("attributed") or item.get("attribited") else np.nan From 85b045e9ae03484553922e83bb703f5987fecd9a Mon Sep 17 00:00:00 2001 From: Meng Lan Date: Mon, 8 Apr 2024 10:29:26 +0800 Subject: [PATCH 089/112] add develop-promptflow-copilot tutorial --- .../develop-promptflow-copilot/chat-panel.png | Bin 0 -> 332728 bytes .../develop-promptflow-copilot.md | 114 ++++++++++++++++++ .../develop-promptflow-copilot/doc-link.png | Bin 0 -> 129442 bytes .../example-flow.png | Bin 0 -> 31315 bytes .../index-lookup-tool.png | Bin 0 -> 48270 bytes .../select-eval.png | Bin 0 -> 86915 bytes .../trigger-eval.png | Bin 0 -> 36821 bytes 7 files changed, 114 insertions(+) create mode 100644 examples/tutorials/develop-promptflow-copilot/chat-panel.png create mode 100644 examples/tutorials/develop-promptflow-copilot/develop-promptflow-copilot.md create mode 100644 examples/tutorials/develop-promptflow-copilot/doc-link.png create mode 100644 examples/tutorials/develop-promptflow-copilot/example-flow.png create mode 100644 examples/tutorials/develop-promptflow-copilot/index-lookup-tool.png create mode 100644 examples/tutorials/develop-promptflow-copilot/select-eval.png create mode 100644 examples/tutorials/develop-promptflow-copilot/trigger-eval.png diff --git a/examples/tutorials/develop-promptflow-copilot/chat-panel.png b/examples/tutorials/develop-promptflow-copilot/chat-panel.png new file mode 100644 index 0000000000000000000000000000000000000000..12946bdee8806c55163fe91d7d87c7a92e1adf3f GIT binary patch literal 332728 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 z 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

ePi}Le=Mbnoh3~_g>>Z#BUt2)o60u_UMfdBE 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 Date: Thu, 11 Jan 2024 10:17:25 +0800 Subject: [PATCH 003/112] update --- examples/test_data_gen/doc_split.py | 21 +++++++-- .../test_data_gen/pipeline/document_split.yml | 8 ++-- .../pipeline/document_split_src/split.py | 24 +++++----- .../test_data_gen/pipeline/submit_pipeline.py | 45 +++++++++++++------ 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/examples/test_data_gen/doc_split.py b/examples/test_data_gen/doc_split.py index 2bfedb462d8..e3408bea91f 100644 --- a/examples/test_data_gen/doc_split.py +++ b/examples/test_data_gen/doc_split.py @@ -1,3 +1,4 @@ +import argparse import json import os import typing as t @@ -15,9 +16,9 @@ ) -def split_doc(input_file_path: str, output_file_path: str, chunk_size: int): +def split_doc(documents_folder: str, output_file_path: str, chunk_size: int): # load docs - documents = SimpleDirectoryReader(input_file_path).load_data() + documents = SimpleDirectoryReader(documents_folder).load_data() # Convert documents into nodes node_parser = SimpleNodeParser.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) @@ -29,5 +30,19 @@ def split_doc(input_file_path: str, output_file_path: str, chunk_size: int): jsonl_str += json.dumps(json_dict) + "\n" cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") - with open(os.path.join(output_file_path, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + with open(os.path.join(output_file_path, "document-nodes-" + cur_time_str + ".jsonl"), "wt") as text_file: print(f"{jsonl_str}", file=text_file) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--documents_folder", type=str, required=True) + parser.add_argument("--chunk_size", type=int, required=False, default=1024) + parser.add_argument("--document_node_output", type=str, required=True) + args = parser.parse_args() + + print(f"documents_folder path: {args.documents_folder}") + print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") + print(f"document_node_output path: {args.document_node_output}") + + split_doc(args.documents_folder, args.document_node_output, args.chunk_size) diff --git a/examples/test_data_gen/pipeline/document_split.yml b/examples/test_data_gen/pipeline/document_split.yml index bc81e007e21..92092ebe863 100644 --- a/examples/test_data_gen/pipeline/document_split.yml +++ b/examples/test_data_gen/pipeline/document_split.yml @@ -6,13 +6,13 @@ display_name: docSplit0 version: 3 inputs: - doc_split_0_input: + documents_folder: type: uri_folder - doc_split_0_chunk_size: + chunk_size: type: integer outputs: - doc_split_0_output: + document_node_output: type: uri_folder code: ./document_split_src @@ -22,4 +22,4 @@ environment: image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 command: >- - python split.py --doc_split_0_input ${{inputs.doc_split_0_input}} --doc_split_0_chunk_size ${{inputs.doc_split_0_chunk_size}} --doc_split_0_output ${{outputs.doc_split_0_output}} + python split.py --documents_folder ${{inputs.documents_folder}} --chunk_size ${{inputs.chunk_size}} --document_node_output ${{outputs.document_node_output}} diff --git a/examples/test_data_gen/pipeline/document_split_src/split.py b/examples/test_data_gen/pipeline/document_split_src/split.py index 4d1d1cf282b..b33631f8484 100644 --- a/examples/test_data_gen/pipeline/document_split_src/split.py +++ b/examples/test_data_gen/pipeline/document_split_src/split.py @@ -16,32 +16,30 @@ ) parser = argparse.ArgumentParser() -parser.add_argument("--doc_split_0_input", type=str) -parser.add_argument("--doc_split_0_chunk_size", type=int) -parser.add_argument("--doc_split_0_output", type=str) +parser.add_argument("--documents_folder", type=str) +parser.add_argument("--chunk_size", type=int) +parser.add_argument("--document_node_output", type=str) args = parser.parse_args() -print("doc_split_0_input path: %s" % args.doc_split_0_input) -print(f"doc_split_0_chunk_size: {type(args.doc_split_0_chunk_size)}: {args.doc_split_0_chunk_size}") -print("doc_split_0_output path: %s" % args.doc_split_0_output) +print("documents_folder path: %s" % args.documents_folder) +print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") +print("document_node_output path: %s" % args.document_node_output) print("files in input path: ") -arr = os.listdir(args.doc_split_0_input) +arr = os.listdir(args.documents_folder) print(arr) for filename in arr: print("reading file: %s ..." % filename) - with open(os.path.join(args.doc_split_0_input, filename), "r") as handle: + with open(os.path.join(args.documents_folder, filename), "r") as handle: print(handle.read()) # load docs -documents = SimpleDirectoryReader(args.doc_split_0_input).load_data() +documents = SimpleDirectoryReader(args.documents_folder).load_data() # Convert documents into nodes -node_parser = SimpleNodeParser.from_defaults( - chunk_size=args.doc_split_0_chunk_size, chunk_overlap=0, include_metadata=True -) +node_parser = SimpleNodeParser.from_defaults(chunk_size=args.chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) @@ -52,5 +50,5 @@ cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") -with open(os.path.join(args.doc_split_0_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: +with open(os.path.join(args.document_node_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/pipeline/submit_pipeline.py b/examples/test_data_gen/pipeline/submit_pipeline.py index b9567426ee4..d054ce982fa 100644 --- a/examples/test_data_gen/pipeline/submit_pipeline.py +++ b/examples/test_data_gen/pipeline/submit_pipeline.py @@ -1,6 +1,7 @@ import argparse from azure.ai.ml import Input, MLClient, dsl, load_component +from azure.ai.ml.entities import CommandComponent, ParallelComponent from azure.identity import DefaultAzureCredential @@ -16,20 +17,18 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str return ml_client -flow_component = load_component("D:\\proj\\PromptFlow\\docs\\evaluation\\examples\\test_data_gen_flow_2\\flow.dag.yaml") - -doc_component = load_component("D:\\proj\\PromptFlow\\docs\\evaluation\\data_gen_poc\\pipeline\\document_split.yml") - - -data_input = Input(path="D:\\proj\\PromptFlow\\docs\\evaluation\\data_gen_poc\\documents", type="uri_folder") - - @dsl.pipeline def pipeline_func_with_flow( - data, aml_cluster: str, connection_name: str, chunk_size=1024, mini_batch_size=2, max_concurrency_per_instance=2 + data, + doc_split_component: CommandComponent, + flow_component: ParallelComponent, + connection_name: str, # ?? should we override here? + chunk_size=1024, + instance_count=1, + mini_batch_size=2, + max_concurrency_per_instance=2, ): - document_node = doc_component(doc_split_0_input=data, doc_split_0_chunk_size=1024) - document_node.compute = aml_cluster + document_node = doc_split_component(doc_split_0_input=data, doc_split_0_chunk_size=chunk_size) flow_node = flow_component( data=document_node.outputs.doc_split_0_output, @@ -38,22 +37,40 @@ def pipeline_func_with_flow( "generate_test_data": {"connection": "azure_open_ai_connection"}, }, ) - flow_node.compute = aml_cluster + + flow_node.resources.instance_count = instance_count flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance if __name__ == "__main__": + # TODO: Add error handling parser = argparse.ArgumentParser() args = parser.parse_args() parser.add_argument("--scription_id", type=str, help="AzureML workspace subscription id") parser.add_argument("--resource_group", type=str, help="AzureML workspace resource group name") parser.add_argument("--workspace_name", type=str, help="AzureML workspace name") - parser.add_argument("--workspace_name", type=str, help="AzureML workspace name") + parser.add_argument("--documents_folder", type=str, help="Documents folder path") + parser.add_argument("--doc_split_yml", type=str, help="Document split component yml path") + parser.add_argument("--flow_path", type=str, help="Test data generation flow path") + + parser.add_argument("--prs_configs", type=dict, help="Flow ParallelRunStep configs") ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) - pipeline_with_flow = pipeline_func_with_flow(data=data_input) + doc_component = load_component(args.doc_split_yml) + flow_component = load_component(args.flow_path) + + data_input = Input(path=args.documents_folder, type="uri_folder") + + pipeline_with_flow = pipeline_func_with_flow( + data=data_input, + doc_split_component=doc_component, + flow_component=flow_component, + connection_name="azure_open_ai_connection", + **args.prs_configs # TODO: Need to do error handling for parsing configs + ) + pipeline_with_flow.compute.target = args.aml_cluster ml_client.jobs.create_or_update(pipeline_with_flow) From 0ff7f8174d95a86189154ab50fd4e02229cef907 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Fri, 12 Jan 2024 17:50:35 +0800 Subject: [PATCH 004/112] update --- docs/how-to-guides/construct-test-data.md | 4 + .../construct_test_data_flow/flow.dag.yaml | 0 .../test_data_gen/document-nodes-test.jsonl | 10 + .../test_data_gen_local/config.ini | 5 + .../construct_test_data_flow/flow.dag.yaml | 75 ++++++ .../generate_test_data.py | 52 ++++ .../construct_test_data_flow/requirements.txt | 5 + .../construct_test_data_flow/utils.py | 250 ++++++++++++++++++ .../{ => test_data_gen_local}/doc_split.py | 18 +- .../test_data_gen_local/requirements.txt | 1 + .../test_data_gen_local/run_test_data_gen.py | 56 ++++ .../test_data_gen_pipeline/clean_data.yml | 25 ++ .../clean_data_src/clean.py} | 0 .../doc_split_conda.yml} | 0 .../document_split.yml | 2 +- .../document_split_src/split.py | 54 ++++ .../run_test_data_gen_pipeline.py} | 0 17 files changed, 552 insertions(+), 5 deletions(-) delete mode 100644 examples/test_data_gen/construct_test_data_flow/flow.dag.yaml create mode 100644 examples/test_data_gen/document-nodes-test.jsonl create mode 100644 examples/test_data_gen/test_data_gen_local/config.ini create mode 100644 examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml create mode 100644 examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py create mode 100644 examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt create mode 100644 examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py rename examples/test_data_gen/{ => test_data_gen_local}/doc_split.py (75%) create mode 100644 examples/test_data_gen/test_data_gen_local/requirements.txt create mode 100644 examples/test_data_gen/test_data_gen_local/run_test_data_gen.py create mode 100644 examples/test_data_gen/test_data_gen_pipeline/clean_data.yml rename examples/test_data_gen/{pipeline/document_split_src/split.py => test_data_gen_pipeline/clean_data_src/clean.py} (100%) rename examples/test_data_gen/{pipeline/conda.yml => test_data_gen_pipeline/doc_split_conda.yml} (100%) rename examples/test_data_gen/{pipeline => test_data_gen_pipeline}/document_split.yml (93%) create mode 100644 examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py rename examples/test_data_gen/{pipeline/submit_pipeline.py => test_data_gen_pipeline/run_test_data_gen_pipeline.py} (100%) diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index 67957c83375..90b4198205a 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -13,6 +13,10 @@ Interface: ?? what if the documents folder is in azure blob folder? Or any other possibility? ![Consider](./temp-to-delete/to_consider_doc_split.png) + +In this sample script, the `SimpleDirectoryReader` of llamaindex is used to split the documents into smaller granularity. For more supported file types, please check [here](https://docs.llamaindex.ai/en/stable/module_guides/loading/simpledirectoryreader.html). +more file readers: ?? + ### portal Locally run doc_split script. Then upload the generated doc nodes jsonl file to portal as a data asset. -> In this way, we should at least consider how user can do both process in local and cloud. diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/test_data_gen/document-nodes-test.jsonl b/examples/test_data_gen/document-nodes-test.jsonl new file mode 100644 index 00000000000..369ab79d650 --- /dev/null +++ b/examples/test_data_gen/document-nodes-test.jsonl @@ -0,0 +1,10 @@ +{"document_node": "{\"id_\": \"caf64060-1332-4069-b458-23152b2f2093\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"41017365-74a3-41fc-ae0c-ecf997eb768a\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"68b4e587d4fbc41b04e006b2a50568b747ac3c39e381ee3135d4c14245a7f75d\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", \"text\": \"Connections\\n\\nConnections are for storing information about how to access external services like LLMs: endpoint, api keys etc.\\n\\n- In your local development environment, the connections are persisted in your local machine with keys encrypted.\\n- In Azure AI, connections can be configured to be shared across the entire workspace. Secrets associated with connections are securely persisted in the corresponding Azure Key Vault, adhering to robust security and compliance standards.\\n\\nPrompt flow provides a variety of pre-built connections, including Azure Open AI, Open AI, etc. These pre-built connections enable seamless integration with these resources within the built-in tools. Additionally, you have the flexibility to create custom connection types using key-value pairs, empowering them to tailor the connections to their specific requirements, particularly in Python tools.\\n\\n| Connection type | Built-in tools |\\n| ------------------------------------------------------------ | ------------------------------- |\\n| Azure Open AI | LLM or Python |\\n| Open AI | LLM or Python |\\n| Cognitive Search | Vector DB Lookup or Python |\\n| Serp | Serp API or Python |\\n| Custom | Python |\\n\\nBy leveraging connections in prompt flow, you can easily establish and manage connections to external APIs and data sources, facilitating efficient data exchange and interaction within their AI applications.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"db4c7302-af8a-4c76-b255-ebeebbf6ebf4\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"49d146660c042ebfd906e88964b3e0e109718bd82cb5028b155b6eac23225567\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"caf64060-1332-4069-b458-23152b2f2093\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"text\": \"Next steps\\n\\n- Create connections\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c5c2ab6a-1010-480b-8698-f0a2cbd2affc\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"45b587a27fffb03ba60fc08d97891b419752c6f33c425d6addadd88df084a58b\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", \"file_name\": \"concept-connections.md\", \"file_type\": null, \"file_size\": 2038, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"text\": \"Flows\\n\\nA flow in prompt flow is a DAG of functions (we call them tools). These functions/tools connected via input/output dependencies and executed based on the topology by prompt flow executor.\\n\\nA flow is represented as a YAML file and can be visualized with our Prompt flow for VS Code extension. Here is an example:\\n\\n!flow_dag\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9b01685e-881f-475e-9ed4-b9bb42980041\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"57395fb0fcaa5f499bb9f4539ca4e9c71f76ae8ccad7f605fb7e6559cd12107a\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"8049fd78-f8ec-40af-8507-47b2477a833a\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"78405dee4fa54a37dc08a634ecc1b5e743052d4ede6e2daf0911312119a6d93f\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"text\": \"Flow types\\n\\nPrompt flow has three flow types:\\n\\n- **Standard flow** and **Chat flow**: these two are for you to develop your LLM application. The primary difference between the two lies in the additional support provided by the \\\"Chat Flow\\\" for chat applications. For instance, you can define chat_history, chat_input, and chat_output for your flow. The prompt flow, in turn, will offer a chat-like experience (including conversation history) during the development of the flow. Moreover, it also provides a sample chat application for deployment purposes.\\n- **Evaluation flow** is for you to test/evaluate the quality of your LLM application (standard/chat flow). It usually run on the outputs of standard/chat flow, and compute some metrics that can be used to determine whether the standard/chat flow performs well. E.g. is the answer accurate? is the answer fact-based?\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"c7ee995b-7278-4bc1-8351-0acea12bd8e0\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"b1d47d4842372c06fa6f32e096456350fdd5cb9ea85026dd34cd72e8114ae9c9\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"0e5d33a5-ae10-4ed0-a786-866cdbb7ad51\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a4dc48f29f69e0c167b442dd34a2c74fd7dd65e58914d472986e0873bb4ef9ed\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"text\": \"When to use standard flow vs. chat flow?\\n\\nAs a general guideline, if you are building a chatbot that needs to maintain conversation history, try chat flow. In most other cases, standard flow should serve your needs.\\n\\nOur examples should also give you an idea when to use what:\\n- examples/flows/standard\\n- examples/flows/chat\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"d2779b59-1578-4ae4-933c-4c3a6821bf35\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"3b0a9030ace8da8e4737290468dab2dbf390816d1bbac689514007ce41339e1e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"feffe22c-ab4b-402e-b85a-13b7a85a1c1b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"ab823744ec4d99c48d3abe4ee314efee9cc37bcaa9296a31155df10d0e93f64b\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"text\": \"Next steps\\n\\n- Quick start\\n- Initialize and test a flow\\n- Run and evaluate a flow\\n- Tune prompts using variants\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"e371bf49-67a8-4b98-bcf2-12a77e25896c\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"180b5669b22aa8a191ffad7db1be8bec23c03ce2d96af4fcce0e25234608b353\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"d113fede-dd92-4908-abd8-b07d9fc48021\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-flows.md\", \"file_name\": \"concept-flows.md\", \"file_type\": null, \"file_size\": 2516, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"c1b036af3fe5d2ab086c20eca55d2e1b03e26eafdaa38ecfed0f8018174b4609\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"text\": \"Tools\\n\\nPrompt flow provides 3 basic tools:\\n- LLM: The LLM tool allows you to write custom prompts and leverage large language models to achieve specific goals, such as summarizing articles, generating customer support responses, and more.\\n- Python: The Python tool enables you to write custom Python functions to perform various tasks, such as fetching web pages, processing intermediate data, calling third-party APIs, and more.\\n- Prompt: The Prompt tool allows you to prepare a prompt as a string for more complex use cases or for use in conjunction with other prompt tools or python tools.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"85765c00-82e9-437f-a117-9cdf60b63912\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"3dfe75d3b547f6773fc4b1e6f00d6d6f61fc935c809a6b2c1ba2c11cba9f6463\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"ce02654d-b82d-4a68-9a7e-3c03fe5aae2c\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4bb28c0bf4a89bebf97658309f169ec42ccdf7407e58fa852461092a4f15d2f1\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"text\": \"More tools\\n\\nOur partners also contributes other useful tools for advanced scenarios, here are some links:\\n- Vector DB Lookup: vector search tool that allows users to search top k similar vectors from vector database.\\n- Faiss Index Lookup: querying within a user-provided Faiss-based vector store.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"b43b95e3-8922-4ab3-8d7b-a68483744e36\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"70b917aabd4d8716f7449760089f5d8c9f6ab6087982d221edfc6634343a900f\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"27d0e658-428f-4765-8272-89dc41c73f6b\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"85c573f0c8f90e6cb961c25e1bcfa95c52b15ee75ef34d2be9d1e83e8dbbda83\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"89acf666-f0a1-46eb-bd01-37132c001785\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"af92a6dde83927644357601cf0d5a2eb051f70052b0df437f0e38d7ca089d8f3\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"text\": \"Custom tools\\n\\nYou can create your own tools that can be shared with your team or anyone in the world. \\nLearn more on Create and Use Tool Package\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} +{"document_node": "{\"id_\": \"89acf666-f0a1-46eb-bd01-37132c001785\", \"embedding\": null, \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": \"9c255c14-bfe1-4fac-b228-e6d9b3feebf7\", \"node_type\": \"4\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"f4050ac206960c9b5b61a8af7547f6828c601115e1ef46fbfff321ed1114309e\", \"class_name\": \"RelatedNodeInfo\"}, \"2\": {\"node_id\": \"78cc3aec-379b-430a-a5dd-c9c1b5152350\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-tools.md\", \"file_name\": \"concept-tools.md\", \"file_type\": null, \"file_size\": 1841, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"4319e7a165f1ffef8479e28f8488394b2b579d270d05e427f4bb7efd0bc1fd5c\", \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": \"6e76c978-dbba-4dbd-b223-27d6a9f8bedb\", \"node_type\": \"1\", \"metadata\": {\"file_path\": \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-variants.md\", \"file_name\": \"concept-variants.md\", \"file_type\": null, \"file_size\": 2608, \"creation_date\": \"2024-01-11\", \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": \"2024-01-11\"}, \"hash\": \"a3d16a55ca08b91123b79ec62e83cdffdc2a691916ba7d365a95f2c2f10071ae\", \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": \"af92a6dde83927644357601cf0d5a2eb051f70052b0df437f0e38d7ca089d8f3\", \"text\": \"Next steps\\n\\nFor more information on the available tools and their usage, visit the our reference doc.\", \"start_char_idx\": null, \"end_char_idx\": null, \"text_template\": \"{metadata_str}\\n\\n{content}\", \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": \"\\n\", \"class_name\": \"TextNode\"}"} diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini new file mode 100644 index 00000000000..8719fbd2fdc --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -0,0 +1,5 @@ +documents_folder = "" +document_chunk_size = 1024 +document_nodes_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" +flow_folder = "D:\proj\github\ms\promptflow\examples\test_data_gen\test_data_gen_local\construct_test_data_flow" +flow_batch_run_size = 10 diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml new file mode 100644 index 00000000000..f56a7d8fe04 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml @@ -0,0 +1,75 @@ +inputs: + document_node: + type: string + default: '"{\"id_\": \"caf64060-1332-4069-b458-23152b2f2093\", \"embedding\": + null, \"metadata\": {\"file_path\": + \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", + \"file_name\": \"concept-connections.md\", \"file_type\": null, + \"file_size\": 2038, \"creation_date\": \"2024-01-11\", + \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": + \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", + \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", + \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", + \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", + \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": + \"41017365-74a3-41fc-ae0c-ecf997eb768a\", \"node_type\": \"4\", + \"metadata\": {\"file_path\": + \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", + \"file_name\": \"concept-connections.md\", \"file_type\": null, + \"file_size\": 2038, \"creation_date\": \"2024-01-11\", + \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": + \"2024-01-11\"}, \"hash\": + \"68b4e587d4fbc41b04e006b2a50568b747ac3c39e381ee3135d4c14245a7f75d\", + \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": + \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", + \"metadata\": {\"file_path\": + \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", + \"file_name\": \"concept-connections.md\", \"file_type\": null, + \"file_size\": 2038, \"creation_date\": \"2024-01-11\", + \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": + \"2024-01-11\"}, \"hash\": + \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", + \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": + \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", + \"text\": \"Connections\\n\\nConnections are for storing information about + how to access external services like LLMs: endpoint, api keys etc.\\n\\n- + In your local development environment, the connections are persisted in + your local machine with keys encrypted.\\n- In Azure AI, connections can + be configured to be shared across the entire workspace. Secrets associated + with connections are securely persisted in the corresponding Azure Key + Vault, adhering to robust security and compliance standards.\\n\\nPrompt + flow provides a variety of pre-built connections, including Azure Open AI, + Open AI, etc. These pre-built connections enable seamless integration with + these resources within the built-in tools. Additionally, you have the + flexibility to create custom connection types using key-value pairs, + empowering them to tailor the connections to their specific requirements, + particularly in Python tools.\\n\\n| Connection + type | Built-in + tools |\\n| + ------------------------------------------------------------ | + ------------------------------- |\\n| Azure Open AI | LLM or + Python |\\n| Open AI | LLM + or Python |\\n| Cognitive Search | Vector DB Lookup or + Python |\\n| Serp | Serp API or + Python |\\n| + Custom | + Python |\\n\\nBy leveraging connections in prompt + flow, you can easily establish and manage connections to external APIs and + data sources, facilitating efficient data exchange and interaction within + their AI applications.\", \"start_char_idx\": null, \"end_char_idx\": + null, \"text_template\": \"{metadata_str}\\n\\n{content}\", + \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": + \"\\n\", \"class_name\": \"TextNode\"}"' +outputs: + test_data: + type: string + reference: ${generate_test_data.output} +nodes: +- name: generate_test_data + type: python + source: + type: code + path: generate_test_data.py + inputs: + connection: azure_open_ai_connection + document_node_str: ${inputs.document_node} diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py new file mode 100644 index 00000000000..4d543bd3aa4 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py @@ -0,0 +1,52 @@ +import json +import os + +from langchain.chat_models import AzureChatOpenAI +from langchain.embeddings import AzureOpenAIEmbeddings +from llama_index.schema import TextNode +from ragas.llms import LangchainLLM +from utils import TestsetGeneratorV2 + +from promptflow import tool +from promptflow.connections import AzureOpenAIConnection + + +# The inputs section will change based on the arguments of the tool function, after you save the code +# Adding type to arguments and return value will help the system show the types properly +# Please update the function name/signature per need +@tool +def my_python_tool(connection: AzureOpenAIConnection, document_node_str: str) -> dict: + + os.environ["AZURE_OPENAI_API_KEY"] = connection.api_key + os.environ["AZURE_OPENAI_ENDPOINT"] = connection.api_base + os.environ["OPENAI_API_VERSION"] = connection.api_version + + azure_model = AzureChatOpenAI(deployment_name="gpt-4", model="gpt-4") + + azure_embeddings = AzureOpenAIEmbeddings(deployment="text-embedding-ada-002", model="text-embedding-ada-002") + + generator_llm = LangchainLLM(llm=azure_model) + critic_llm = LangchainLLM(llm=azure_model) + embeddings_model = azure_embeddings + + testset_distribution = { + "simple": 1, + "reasoning": 0, + "multi_context": 0, + "conditional": 0, + } + + test_generator = TestsetGeneratorV2( + generator_llm=generator_llm, + critic_llm=critic_llm, + embeddings_model=embeddings_model, + testset_distribution=testset_distribution, + chat_qa=0, + ) + + json_dict = json.loads(document_node_str) + document_node = TextNode.from_json(json_dict) + + test_data = test_generator.generate(document_node=document_node) + + return test_data diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt new file mode 100644 index 00000000000..457b813a4e4 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt @@ -0,0 +1,5 @@ +promptflow[azure] +python-dotenv +bs4 +llama_index +ragas diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py new file mode 100644 index 00000000000..24c14f28b1d --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py @@ -0,0 +1,250 @@ +from __future__ import annotations + +import typing as t +import warnings +from collections import defaultdict + +try: + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + +import numpy as np +import numpy.testing as npt +from langchain.embeddings import OpenAIEmbeddings +from langchain.embeddings.base import Embeddings +from langchain.prompts import ChatPromptTemplate +from numpy.random import default_rng +from ragas.llms import llm_factory +from ragas.testset.prompts import ( + ANSWER_FORMULATE, + COMPRESS_QUESTION, + CONDITIONAL_QUESTION, + CONTEXT_FORMULATE, + CONVERSATION_QUESTION, + FILTER_QUESTION, + MULTICONTEXT_QUESTION, + REASONING_QUESTION, + SCORE_CONTEXT, + SEED_QUESTION, +) +from ragas.testset.utils import load_as_json, load_as_score + +if t.TYPE_CHECKING: + from ragas.llms.base import RagasLLM + + +DEFAULT_TEST_DISTRIBUTION = { + "simple": 0.4, + "reasoning": 0.2, + "multi_context": 0.2, + "conditional": 0.2, +} + + +class TestsetGeneratorV2: + + """ + Ragas Test Set Generator + + Attributes + ---------- + generator_llm: LangchainLLM + LLM used for all the generator operations in the TestGeneration paradigm. + critique_llm: LangchainLLM + LLM used for all the filtering and scoring operations in TestGeneration + paradigm. + embeddings_model: Embeddings + Embeddings used for vectorizing nodes when required. + chat_qa: float + Determines the fraction of conversational questions the resulting test set. + chunk_size: int + The chunk size of nodes created from data. + test_distribution : dict + Distribution of different types of questions to be generated from given + set of documents. Defaults to {"easy":0.1, "reasoning":0.4, "conversation":0.5} + """ + + def __init__( + self, + generator_llm: RagasLLM, + critic_llm: RagasLLM, + embeddings_model: Embeddings, + testset_distribution: t.Optional[t.Dict[str, float]] = None, + chat_qa: float = 0.0, + chunk_size: int = 1024, + seed: int = 42, + ) -> None: + self.generator_llm = generator_llm + self.critic_llm = critic_llm + self.embedding_model = embeddings_model + testset_distribution = testset_distribution or DEFAULT_TEST_DISTRIBUTION + npt.assert_almost_equal( + 1, + sum(testset_distribution.values()), + err_msg="Sum of distribution should be 1", + ) + + prob = np.cumsum(list(testset_distribution.values())) + types = testset_distribution.keys() + self.testset_distribution = dict(zip(types, prob)) + + self.chat_qa = chat_qa + self.chunk_size = chunk_size + self.threshold = 7.5 + self.rng = default_rng(seed) + + @classmethod + def from_default( + cls, + openai_generator_llm: str = "gpt-3.5-turbo-16k", + openai_filter_llm: str = "gpt-4", + chat_qa: float = 0.3, + chunk_size: int = 512, + testset_distribution: dict = DEFAULT_TEST_DISTRIBUTION, + ): + generator_llm = llm_factory(openai_generator_llm) + critic_llm = llm_factory(openai_filter_llm) + embeddings_model = OpenAIEmbeddings() # type: ignore + return cls( + generator_llm=generator_llm, + critic_llm=critic_llm, + embeddings_model=embeddings_model, + chat_qa=chat_qa, + chunk_size=chunk_size, + testset_distribution=testset_distribution, + ) + + def _get_evolve_type(self) -> str: + """ + Decides question evolution type based on probability + """ + prob = self.rng.uniform(0, 1) + print("yao-debug: evolve type prob:", prob) + return next( + (key for key in self.testset_distribution.keys() if prob <= self.testset_distribution[key]), + "simple", + ) + + def _filter_context(self, context: str) -> bool: + """ + context: str + The input context + + Checks if the context is has information worthy of framing a question + """ + human_prompt = SCORE_CONTEXT.format(context=context) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + results = self.critic_llm.generate(prompts=[prompt]) + output = results.generations[0][0].text.strip() + score = load_as_score(output) + return score >= self.threshold + + def _seed_question(self, context: str) -> str: + human_prompt = SEED_QUESTION.format(context=context) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + results = self.generator_llm.generate(prompts=[prompt]) + return results.generations[0][0].text.strip() + + def _filter_question(self, question: str) -> bool: + human_prompt = FILTER_QUESTION.format(question=question) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + + results = self.critic_llm.generate(prompts=[prompt]) + results = results.generations[0][0].text.strip() + json_results = load_as_json(results) + return json_results.get("verdict") != "No" + + def _reasoning_question(self, question: str, context: str) -> str: + return self._qc_template(REASONING_QUESTION, question, context) + + def _condition_question(self, question: str, context: str) -> str: + return self._qc_template(CONDITIONAL_QUESTION, question, context) + + def _multicontext_question(self, question: str, context1: str, context2: str) -> str: + human_prompt = MULTICONTEXT_QUESTION.format(question=question, context1=context1, context2=context2) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + results = self.generator_llm.generate(prompts=[prompt]) + return results.generations[0][0].text.strip() + + def _compress_question(self, question: str) -> str: + return self._question_transformation(COMPRESS_QUESTION, question=question) + + def _conversational_question(self, question: str) -> str: + return self._question_transformation(CONVERSATION_QUESTION, question=question) + + def _question_transformation(self, prompt, question: str) -> str: + human_prompt = prompt.format(question=question) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + results = self.generator_llm.generate(prompts=[prompt]) + return results.generations[0][0].text.strip() + + def _qc_template(self, prompt, question, context) -> str: + human_prompt = prompt.format(question=question, context=context) + prompt = ChatPromptTemplate.from_messages([human_prompt]) + results = self.generator_llm.generate(prompts=[prompt]) + return results.generations[0][0].text.strip() + + def _generate_answer(self, question: str, context: t.List[str]) -> t.List[str]: + return [self._qc_template(ANSWER_FORMULATE, ques, context[i]) for i, ques in enumerate(question.split("\n"))] + + def _generate_context(self, question: str, text_chunk: str) -> t.List[str]: + return [self._qc_template(CONTEXT_FORMULATE, ques, text_chunk) for ques in question.split("\n")] + + def _remove_nodes(self, available_indices: t.List[BaseNode], node_idx: t.List) -> t.List[BaseNode]: + for idx in node_idx: + available_indices.remove(idx) + return available_indices + + def _generate_doc_nodes_map(self, document_nodes: t.List[BaseNode]) -> t.Dict[str, t.List[BaseNode]]: + doc_nodes_map: t.Dict[str, t.List[BaseNode]] = defaultdict(list) + for node in document_nodes: + if node.ref_doc_id: + doc_nodes_map[node.ref_doc_id].append(node) + + return doc_nodes_map # type: ignore + + def _get_neighbour_node(self, node: BaseNode, related_nodes: t.List[BaseNode]) -> t.List[BaseNode]: + if len(related_nodes) < 2: + warnings.warn("No neighbors exists") + return [node] + idx = related_nodes.index(node) + ids = [idx - 1, idx] if idx == (len(related_nodes) - 1) else [idx, idx + 1] + return [related_nodes[idx] for idx in ids] + + def _embed_nodes(self, nodes: t.List[BaseNode]) -> t.Dict[str, t.List[float]]: + embeddings = {} + for node in nodes: + embeddings[node.id_] = list(self.embedding_model.embed_query(node.get_content())) + + return embeddings + + def generate( + self, + document_node: BaseNode, + ) -> dict: + text_chunk = document_node.get_content() + score = self._filter_context(text_chunk) + if not score: + print("Failed to validate context.") + return {} + seed_question = self._seed_question(text_chunk) + # is_valid_question = self._filter_question(seed_question) + # if not is_valid_question: + # print("The seed question is not valid.") + # return {} + + question = seed_question + context = self._generate_context(question, text_chunk) + answer = self._generate_answer(question, context) + for i, (ques, ctx, ans) in enumerate(zip(question.split("\n"), context, answer)): + my_data_row = { + "question": ques, + "ground_truth_context": ctx, + "ground_truth": ans, + "question_type": "simple", + } + + return my_data_row diff --git a/examples/test_data_gen/doc_split.py b/examples/test_data_gen/test_data_gen_local/doc_split.py similarity index 75% rename from examples/test_data_gen/doc_split.py rename to examples/test_data_gen/test_data_gen_local/doc_split.py index e3408bea91f..ff8e4ca90df 100644 --- a/examples/test_data_gen/doc_split.py +++ b/examples/test_data_gen/test_data_gen_local/doc_split.py @@ -5,9 +5,10 @@ from datetime import datetime from llama_index import SimpleDirectoryReader +from llama_index.readers import BeautifulSoupWebReader try: - from llama_index.node_parser import SimpleNodeParser + from llama_index.node_parser import SentenceSplitter from llama_index.readers.schema import Document as LlamaindexDocument from llama_index.schema import BaseNode except ImportError: @@ -16,11 +17,20 @@ ) -def split_doc(documents_folder: str, output_file_path: str, chunk_size: int): +def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, urls: list = None): # load docs - documents = SimpleDirectoryReader(documents_folder).load_data() + if urls: + documents = BeautifulSoupWebReader().load_data(urls=urls) + else: + documents = SimpleDirectoryReader( + documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" + ).load_data() + + doc_info = [doc.metadata["file_name"] for doc in documents] + print(f"documents: {doc_info}") + # Convert documents into nodes - node_parser = SimpleNodeParser.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) + node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) diff --git a/examples/test_data_gen/test_data_gen_local/requirements.txt b/examples/test_data_gen/test_data_gen_local/requirements.txt new file mode 100644 index 00000000000..8b0115aa698 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/requirements.txt @@ -0,0 +1 @@ +configargparse diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py new file mode 100644 index 00000000000..6b775304de6 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -0,0 +1,56 @@ +from datetime import datetime + +import configargparse + +from promptflow import PFClient +from promptflow.entities import Run + + +def batch_run_flow(pf: PFClient, flow_folder: str, flow_input_data: str, flow_batch_run_size: int): + environment_variables = { + "PF_WORKER_COUNT": str(flow_batch_run_size), + "PF_BATCH_METHOD": "spawn", + } # TODO: what does 'spawn' mean? + + print("start to run batch flow run.") + # create run + base_run = pf.run( + flow=flow_folder, + data=flow_input_data, + stream=True, # TODO: understand 'stream' + environment_variables=environment_variables, + column_mapping={"document_node": "${data.document_node}"}, + debug=True, + ) + + return base_run + + +def get_batch_run_output(pf: PFClient, base_run: Run): + print("start to get batch flow run details.") + # get run output + details = pf.get_details(base_run) + + return details.output + + +if __name__ == "__main__": + parser = configargparse.ArgParser(default_config_files=["./config.ini"]) + parser.add("--documents_folder", required=True, help="Documents folder path") + parser.add("--document_chunk_size", required=False, help="Document chunk size, default is 1024") + parser.add("--document_nodes_output_path", required=False, help="Document nodes output path, default is ./") + parser.add("--flow_folder", required=True, help="Test data generation flow folder path") + parser.add("--flow_batch_run_size", required=False, help="Test data generation flow batch run size, default is 16") + args = parser.parse_args() + + pf = PFClient() + # TODO: error handling + print( + f"yao-debug: flow_folder: {args.flow_folder}, document_nodes_output_path: {args.document_nodes_output_path}", + f"flow_batch_run_size: {args.flow_batch_run_size}\n", + ) + print(f"batch run start time: {datetime.now()}") + batch_run = batch_run_flow(pf, args.flow_folder, args.document_nodes_output_path, args.flow_batch_run_size) + print(f"batch run end time: {datetime.now()}") + test_data_set = pf.get_details(batch_run) + print(test_data_set) diff --git a/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml b/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml new file mode 100644 index 00000000000..db56a84025c --- /dev/null +++ b/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml @@ -0,0 +1,25 @@ +$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json +type: command + +name: doc_split_0 +display_name: docSplit0 +version: 3 + +inputs: + documents_folder: + type: uri_folder + chunk_size: + type: integer + +outputs: + document_node_output: + type: uri_folder + +code: ./document_split_src + +environment: + conda_file: ./doc_split_conda.yml + image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 + +command: >- + python split.py --documents_folder ${{inputs.documents_folder}} --chunk_size ${{inputs.chunk_size}} --document_node_output ${{outputs.document_node_output}} diff --git a/examples/test_data_gen/pipeline/document_split_src/split.py b/examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py similarity index 100% rename from examples/test_data_gen/pipeline/document_split_src/split.py rename to examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py diff --git a/examples/test_data_gen/pipeline/conda.yml b/examples/test_data_gen/test_data_gen_pipeline/doc_split_conda.yml similarity index 100% rename from examples/test_data_gen/pipeline/conda.yml rename to examples/test_data_gen/test_data_gen_pipeline/doc_split_conda.yml diff --git a/examples/test_data_gen/pipeline/document_split.yml b/examples/test_data_gen/test_data_gen_pipeline/document_split.yml similarity index 93% rename from examples/test_data_gen/pipeline/document_split.yml rename to examples/test_data_gen/test_data_gen_pipeline/document_split.yml index 92092ebe863..db56a84025c 100644 --- a/examples/test_data_gen/pipeline/document_split.yml +++ b/examples/test_data_gen/test_data_gen_pipeline/document_split.yml @@ -18,7 +18,7 @@ outputs: code: ./document_split_src environment: - conda_file: ./conda.yml + conda_file: ./doc_split_conda.yml image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 command: >- diff --git a/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py b/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py new file mode 100644 index 00000000000..b33631f8484 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py @@ -0,0 +1,54 @@ +import argparse +import json +import os +import typing as t +from datetime import datetime + +from llama_index import SimpleDirectoryReader + +try: + from llama_index.node_parser import SimpleNodeParser + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + +parser = argparse.ArgumentParser() +parser.add_argument("--documents_folder", type=str) +parser.add_argument("--chunk_size", type=int) +parser.add_argument("--document_node_output", type=str) + + +args = parser.parse_args() + +print("documents_folder path: %s" % args.documents_folder) +print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") +print("document_node_output path: %s" % args.document_node_output) + +print("files in input path: ") +arr = os.listdir(args.documents_folder) +print(arr) + +for filename in arr: + print("reading file: %s ..." % filename) + with open(os.path.join(args.documents_folder, filename), "r") as handle: + print(handle.read()) + +# load docs +documents = SimpleDirectoryReader(args.documents_folder).load_data() +# Convert documents into nodes +node_parser = SimpleNodeParser.from_defaults(chunk_size=args.chunk_size, chunk_overlap=0, include_metadata=True) +documents = t.cast(t.List[LlamaindexDocument], documents) +document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) + +jsonl_str = "" +for doc in document_nodes: + json_dict = {"document_node": doc.to_json()} + jsonl_str += json.dumps(json_dict) + "\n" + + +cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") +with open(os.path.join(args.document_node_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/pipeline/submit_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py similarity index 100% rename from examples/test_data_gen/pipeline/submit_pipeline.py rename to examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py From 9341681acf58d3b96e180f5cfde3d6f0c0271a7e Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Mon, 15 Jan 2024 14:14:17 +0800 Subject: [PATCH 005/112] update --- .../test_data_gen_local/config.ini | 6 +++-- .../generate_test_data.py | 5 ++-- .../test_data_gen_local/run_test_data_gen.py | 24 +++++++++++++++---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini index 8719fbd2fdc..6da0d0c17d0 100644 --- a/examples/test_data_gen/test_data_gen_local/config.ini +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -1,5 +1,7 @@ documents_folder = "" document_chunk_size = 1024 -document_nodes_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" -flow_folder = "D:\proj\github\ms\promptflow\examples\test_data_gen\test_data_gen_local\construct_test_data_flow" +# cspell: ignore luyao +document_nodes_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/document-nodes-test.jsonl" +flow_folder = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/construct_test_data_flow" flow_batch_run_size = 10 +test_data_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/test_data" diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py index 4d543bd3aa4..d7026d7ae56 100644 --- a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py @@ -1,4 +1,3 @@ -import json import os from langchain.chat_models import AzureChatOpenAI @@ -44,8 +43,8 @@ def my_python_tool(connection: AzureOpenAIConnection, document_node_str: str) -> chat_qa=0, ) - json_dict = json.loads(document_node_str) - document_node = TextNode.from_json(json_dict) + # json_dict = json.dumps(document_node_str) + document_node = TextNode.from_json(document_node_str) test_data = test_generator.generate(document_node=document_node) diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py index 6b775304de6..e1622ef36e6 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -1,3 +1,5 @@ +import json +import os from datetime import datetime import configargparse @@ -31,7 +33,19 @@ def get_batch_run_output(pf: PFClient, base_run: Run): # get run output details = pf.get_details(base_run) - return details.output + # TODO: error handling like if the run failed because of rate limit. + + return details["outputs.test_data"].tolist() + + +def get_cleaned_data_and_save(test_data_set: list, test_data_output_path: str): + cleaned_data = [test_data for test_data in test_data_set if test_data] + + jsonl_str = "\n".join(map(json.dumps, cleaned_data)) + + cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") + with open(os.path.join(test_data_output_path, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) if __name__ == "__main__": @@ -41,6 +55,7 @@ def get_batch_run_output(pf: PFClient, base_run: Run): parser.add("--document_nodes_output_path", required=False, help="Document nodes output path, default is ./") parser.add("--flow_folder", required=True, help="Test data generation flow folder path") parser.add("--flow_batch_run_size", required=False, help="Test data generation flow batch run size, default is 16") + parser.add("--test_data_output_path", required=True, help="Test data output path.") args = parser.parse_args() pf = PFClient() @@ -49,8 +64,7 @@ def get_batch_run_output(pf: PFClient, base_run: Run): f"yao-debug: flow_folder: {args.flow_folder}, document_nodes_output_path: {args.document_nodes_output_path}", f"flow_batch_run_size: {args.flow_batch_run_size}\n", ) - print(f"batch run start time: {datetime.now()}") batch_run = batch_run_flow(pf, args.flow_folder, args.document_nodes_output_path, args.flow_batch_run_size) - print(f"batch run end time: {datetime.now()}") - test_data_set = pf.get_details(batch_run) - print(test_data_set) + + test_data_set = get_batch_run_output(pf, batch_run) + get_cleaned_data_and_save(test_data_set, args.test_data_output_path) From d81e8985eeb264d7ffb4181311aadb7beb5aa9fd Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:53:47 +0800 Subject: [PATCH 006/112] update --- .../test_data_gen_local/config.ini | 2 + .../construct_test_data_flow/flow.dag.yaml | 3 + .../construct_test_data_flow/requirements.txt | 2 +- .../test_data_gen_pipeline/clean_data.yml | 25 ----- .../clean_data_src/clean.py | 54 ---------- .../test_data_gen_pipeline/components.py | 99 +++++++++++++++++++ .../{doc_split_conda.yml => conda.yml} | 3 +- .../test_data_gen_pipeline/config.ini | 17 ++++ .../test_data_gen_pipeline/document_split.yml | 25 ----- .../document_split_src/split.py | 54 ---------- .../run_test_data_gen_pipeline.py | 58 ++++++----- 11 files changed, 159 insertions(+), 183 deletions(-) delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/clean_data.yml delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py create mode 100644 examples/test_data_gen/test_data_gen_pipeline/components.py rename examples/test_data_gen/test_data_gen_pipeline/{doc_split_conda.yml => conda.yml} (63%) create mode 100644 examples/test_data_gen/test_data_gen_pipeline/config.ini delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/document_split.yml delete mode 100644 examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini index 6da0d0c17d0..2f23422ec7e 100644 --- a/examples/test_data_gen/test_data_gen_local/config.ini +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -2,6 +2,8 @@ documents_folder = "" document_chunk_size = 1024 # cspell: ignore luyao document_nodes_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/document-nodes-test.jsonl" +# test data gen flow configs flow_folder = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/construct_test_data_flow" flow_batch_run_size = 10 +# test data output path test_data_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/test_data" diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml index f56a7d8fe04..e984071c6a2 100644 --- a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml @@ -1,3 +1,6 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json +environment: + python_requirements_txt: requirements.txt inputs: document_node: type: string diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt index 457b813a4e4..65274d176b2 100644 --- a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt +++ b/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt @@ -2,4 +2,4 @@ promptflow[azure] python-dotenv bs4 llama_index -ragas +ragas==0.0.21 diff --git a/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml b/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml deleted file mode 100644 index db56a84025c..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml +++ /dev/null @@ -1,25 +0,0 @@ -$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json -type: command - -name: doc_split_0 -display_name: docSplit0 -version: 3 - -inputs: - documents_folder: - type: uri_folder - chunk_size: - type: integer - -outputs: - document_node_output: - type: uri_folder - -code: ./document_split_src - -environment: - conda_file: ./doc_split_conda.yml - image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 - -command: >- - python split.py --documents_folder ${{inputs.documents_folder}} --chunk_size ${{inputs.chunk_size}} --document_node_output ${{outputs.document_node_output}} diff --git a/examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py b/examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py deleted file mode 100644 index b33631f8484..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/clean_data_src/clean.py +++ /dev/null @@ -1,54 +0,0 @@ -import argparse -import json -import os -import typing as t -from datetime import datetime - -from llama_index import SimpleDirectoryReader - -try: - from llama_index.node_parser import SimpleNodeParser - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - -parser = argparse.ArgumentParser() -parser.add_argument("--documents_folder", type=str) -parser.add_argument("--chunk_size", type=int) -parser.add_argument("--document_node_output", type=str) - - -args = parser.parse_args() - -print("documents_folder path: %s" % args.documents_folder) -print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") -print("document_node_output path: %s" % args.document_node_output) - -print("files in input path: ") -arr = os.listdir(args.documents_folder) -print(arr) - -for filename in arr: - print("reading file: %s ..." % filename) - with open(os.path.join(args.documents_folder, filename), "r") as handle: - print(handle.read()) - -# load docs -documents = SimpleDirectoryReader(args.documents_folder).load_data() -# Convert documents into nodes -node_parser = SimpleNodeParser.from_defaults(chunk_size=args.chunk_size, chunk_overlap=0, include_metadata=True) -documents = t.cast(t.List[LlamaindexDocument], documents) -document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - -jsonl_str = "" -for doc in document_nodes: - json_dict = {"document_node": doc.to_json()} - jsonl_str += json.dumps(json_dict) + "\n" - - -cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") -with open(os.path.join(args.document_node_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: - print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/test_data_gen_pipeline/components.py b/examples/test_data_gen/test_data_gen_pipeline/components.py new file mode 100644 index 00000000000..525680d5b85 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_pipeline/components.py @@ -0,0 +1,99 @@ +import json +import os +import typing as t +from pathlib import Path + +from mldesigner import Input, Output, command_component + +try: + from llama_index import SimpleDirectoryReader + from llama_index.node_parser import SentenceSplitter + from llama_index.readers.schema import Document as LlamaindexDocument + from llama_index.schema import BaseNode +except ImportError: + raise ImportError( + "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." + ) + +TEST_DATA_KEY = "test_data" + + +@command_component( + name="document_split", + version="1", + display_name="Split documents", + description="Split documents into chunks.", + environment=dict( + conda_file=Path(__file__).parent / "conda.yml", + image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", + ), +) +def document_split( + documents_folder: Input(type="uri_folder"), chunk_size: int, document_node_output: Output(type="uri_folder") +) -> str: + """Split documents into chunks. + + Args: + documents_folder: The folder containing documents to be split. + chunk_size: The size of each chunk. + + Returns: + The folder containing the split documents. + """ + print("files in input path: ") + arr = os.listdir(documents_folder) + print(arr) + + # load docs + documents = SimpleDirectoryReader( + documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" + ).load_data() + # Convert documents into nodes + node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) + documents = t.cast(t.List[LlamaindexDocument], documents) + document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) + + jsonl_str = "" + for doc in document_nodes: + json_dict = {"document_node": doc.to_json()} + jsonl_str += json.dumps(json_dict) + "\n" + + with open(os.path.join(document_node_output, "document_nodes.jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) + + return str((Path(document_node_output) / "document_nodes.jsonl")) + + +@command_component( + name="clean_test_data_set", + version="1", + display_name="Clean dataset", + description="Clean test data set to remove empty lines.", + environment=dict( + conda_file=Path(__file__).parent / "conda.yml", + image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04", + ), +) +def clean_test_data_set( + test_data_set_folder: Input(type="uri_folder"), test_data_output: Output(type="uri_folder") +) -> str: + test_data_set_path = Path(test_data_set_folder) / "parallel_run_step.jsonl" + print("test_data_file path: %s" % test_data_set_path) + + print("reading file: %s ..." % test_data_set_path) + with open(test_data_set_path, "r") as f: + print(f.read()) + data = [json.loads(line) for line in f] + + # Filter out empty dictionaries + # TODO: error handling + filtered_data = [d for d in data if d[TEST_DATA_KEY]] + + jsonl_str = "" + for d in filtered_data: + jsonl_str += json.dumps(d[TEST_DATA_KEY]) + "\n" + + with open(os.path.join(test_data_output, "test_data_set.jsonl"), "wt") as text_file: + print(f"{jsonl_str}", file=text_file) + + return str((Path(test_data_output) / "test_data_set.jsonl")) diff --git a/examples/test_data_gen/test_data_gen_pipeline/doc_split_conda.yml b/examples/test_data_gen/test_data_gen_pipeline/conda.yml similarity index 63% rename from examples/test_data_gen/test_data_gen_pipeline/doc_split_conda.yml rename to examples/test_data_gen/test_data_gen_pipeline/conda.yml index d6151f619be..6ffb3338c0d 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/doc_split_conda.yml +++ b/examples/test_data_gen/test_data_gen_pipeline/conda.yml @@ -1,8 +1,9 @@ -name: doc_split_conda_env +name: test_data_gen_conda_env channels: - defaults dependencies: - python=3.10.12 - pip=23.2.1 - pip: + - mldesigner==0.1.0b17 - llama_index diff --git a/examples/test_data_gen/test_data_gen_pipeline/config.ini b/examples/test_data_gen/test_data_gen_pipeline/config.ini new file mode 100644 index 00000000000..50e080266d2 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_pipeline/config.ini @@ -0,0 +1,17 @@ +subscription_id = "96aede12-2f73-41cb-b983-6d11a904839b" +resource_group = "promptflow" +# cspell: ignore yaopfeus +workspace_name = "yaopfeus" +aml_cluster = "cpu-cluster" +# cspell: ignore luyao +documents_folder = "/Users/luyao/proj/promptflow/docs/how-to-guides/develop-a-tool" +doc_split_yml = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_pipeline/document_split.yml" +document_chunk_size = 1024 +# test data gen flow configs +flow_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml" +# Parallel run step configs +prs_instance_count = 2 +prs_mini_batch_size = "100kb" +prs_max_concurrency_per_instance = 10 +# clean data +clean_data_yml = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml" diff --git a/examples/test_data_gen/test_data_gen_pipeline/document_split.yml b/examples/test_data_gen/test_data_gen_pipeline/document_split.yml deleted file mode 100644 index db56a84025c..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/document_split.yml +++ /dev/null @@ -1,25 +0,0 @@ -$schema: https://azuremlschemas.azureedge.net/latest/commandComponent.schema.json -type: command - -name: doc_split_0 -display_name: docSplit0 -version: 3 - -inputs: - documents_folder: - type: uri_folder - chunk_size: - type: integer - -outputs: - document_node_output: - type: uri_folder - -code: ./document_split_src - -environment: - conda_file: ./doc_split_conda.yml - image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04 - -command: >- - python split.py --documents_folder ${{inputs.documents_folder}} --chunk_size ${{inputs.chunk_size}} --document_node_output ${{outputs.document_node_output}} diff --git a/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py b/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py deleted file mode 100644 index b33631f8484..00000000000 --- a/examples/test_data_gen/test_data_gen_pipeline/document_split_src/split.py +++ /dev/null @@ -1,54 +0,0 @@ -import argparse -import json -import os -import typing as t -from datetime import datetime - -from llama_index import SimpleDirectoryReader - -try: - from llama_index.node_parser import SimpleNodeParser - from llama_index.readers.schema import Document as LlamaindexDocument - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) - -parser = argparse.ArgumentParser() -parser.add_argument("--documents_folder", type=str) -parser.add_argument("--chunk_size", type=int) -parser.add_argument("--document_node_output", type=str) - - -args = parser.parse_args() - -print("documents_folder path: %s" % args.documents_folder) -print(f"chunk_size: {type(args.chunk_size)}: {args.chunk_size}") -print("document_node_output path: %s" % args.document_node_output) - -print("files in input path: ") -arr = os.listdir(args.documents_folder) -print(arr) - -for filename in arr: - print("reading file: %s ..." % filename) - with open(os.path.join(args.documents_folder, filename), "r") as handle: - print(handle.read()) - -# load docs -documents = SimpleDirectoryReader(args.documents_folder).load_data() -# Convert documents into nodes -node_parser = SimpleNodeParser.from_defaults(chunk_size=args.chunk_size, chunk_overlap=0, include_metadata=True) -documents = t.cast(t.List[LlamaindexDocument], documents) -document_nodes: t.List[BaseNode] = node_parser.get_nodes_from_documents(documents=documents) - -jsonl_str = "" -for doc in document_nodes: - json_dict = {"document_node": doc.to_json()} - jsonl_str += json.dumps(json_dict) + "\n" - - -cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") -with open(os.path.join(args.document_node_output, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: - print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index d054ce982fa..65409af4c18 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -1,8 +1,7 @@ -import argparse - +import configargparse from azure.ai.ml import Input, MLClient, dsl, load_component -from azure.ai.ml.entities import CommandComponent, ParallelComponent from azure.identity import DefaultAzureCredential +from components import clean_test_data_set, document_split def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): @@ -17,60 +16,73 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str return ml_client -@dsl.pipeline +@dsl.pipeline( + # default_compute_target="cpucluster", + non_pipeline_inputs=["flow_yml_path", "instance_count", "mini_batch_size", "max_concurrency_per_instance"] +) def pipeline_func_with_flow( data, - doc_split_component: CommandComponent, - flow_component: ParallelComponent, + flow_yml_path: str, connection_name: str, # ?? should we override here? chunk_size=1024, instance_count=1, - mini_batch_size=2, + mini_batch_size="10kb", max_concurrency_per_instance=2, ): - document_node = doc_split_component(doc_split_0_input=data, doc_split_0_chunk_size=chunk_size) + document_node = document_split(documents_folder=data, chunk_size=chunk_size) + flow_component = load_component(flow_yml_path) flow_node = flow_component( - data=document_node.outputs.doc_split_0_output, + data=document_node.outputs.document_node_output, document_node="${data.document_node}", connections={ "generate_test_data": {"connection": "azure_open_ai_connection"}, }, ) - flow_node.resources.instance_count = instance_count flow_node.mini_batch_size = mini_batch_size flow_node.max_concurrency_per_instance = max_concurrency_per_instance + flow_node.set_resources(instance_count=instance_count) + + clean_test_data_set(test_data_set_folder=flow_node.outputs.flow_outputs) if __name__ == "__main__": # TODO: Add error handling - parser = argparse.ArgumentParser() - args = parser.parse_args() - parser.add_argument("--scription_id", type=str, help="AzureML workspace subscription id") + parser = configargparse.ArgParser(default_config_files=["./config.ini"]) + parser.add_argument("--subscription_id", type=str, help="AzureML workspace subscription id") parser.add_argument("--resource_group", type=str, help="AzureML workspace resource group name") parser.add_argument("--workspace_name", type=str, help="AzureML workspace name") - + parser.add_argument("--aml_cluster", type=str, help="AzureML cluster name") parser.add_argument("--documents_folder", type=str, help="Documents folder path") parser.add_argument("--doc_split_yml", type=str, help="Document split component yml path") + parser.add_argument("--document_chunk_size", type=int, help="Document chunk size") parser.add_argument("--flow_path", type=str, help="Test data generation flow path") - - parser.add_argument("--prs_configs", type=dict, help="Flow ParallelRunStep configs") + parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") + parser.add_argument("--prs_mini_batch_size", type=str, help="Parallel run step mini batch size") + parser.add_argument( + "--prs_max_concurrency_per_instance", type=int, help="Parallel run step max concurrency per instance" + ) + parser.add_argument("--clean_data_yml", type=str, help="Clean data component yml path") + args = parser.parse_args() ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) - doc_component = load_component(args.doc_split_yml) - flow_component = load_component(args.flow_path) - data_input = Input(path=args.documents_folder, type="uri_folder") + prs_configs = { + "instance_count": args.prs_instance_count, + "mini_batch_size": args.prs_mini_batch_size, + "max_concurrency_per_instance": args.prs_max_concurrency_per_instance, + } + pipeline_with_flow = pipeline_func_with_flow( data=data_input, - doc_split_component=doc_component, - flow_component=flow_component, + flow_yml_path=args.flow_path, connection_name="azure_open_ai_connection", - **args.prs_configs # TODO: Need to do error handling for parsing configs + chunk_size=args.document_chunk_size, + **prs_configs # TODO: Need to do error handling for parsing configs ) - pipeline_with_flow.compute.target = args.aml_cluster + pipeline_with_flow.compute = args.aml_cluster ml_client.jobs.create_or_update(pipeline_with_flow) From 0c39bf27166a35141786900de89f78eb246596a4 Mon Sep 17 00:00:00 2001 From: Yao <46446115+16oeahr@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:56:08 +0800 Subject: [PATCH 007/112] move flow to outside --- .../construct_test_data_flow/flow.dag.yaml | 0 .../construct_test_data_flow/generate_test_data.py | 0 .../construct_test_data_flow/requirements.txt | 0 .../{test_data_gen_local => }/construct_test_data_flow/utils.py | 0 examples/test_data_gen/test_data_gen_local/config.ini | 2 +- examples/test_data_gen/test_data_gen_pipeline/components.py | 1 - examples/test_data_gen/test_data_gen_pipeline/config.ini | 2 +- 7 files changed, 2 insertions(+), 3 deletions(-) rename examples/test_data_gen/{test_data_gen_local => }/construct_test_data_flow/flow.dag.yaml (100%) rename examples/test_data_gen/{test_data_gen_local => }/construct_test_data_flow/generate_test_data.py (100%) rename examples/test_data_gen/{test_data_gen_local => }/construct_test_data_flow/requirements.txt (100%) rename examples/test_data_gen/{test_data_gen_local => }/construct_test_data_flow/utils.py (100%) diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml similarity index 100% rename from examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml rename to examples/test_data_gen/construct_test_data_flow/flow.dag.yaml diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py b/examples/test_data_gen/construct_test_data_flow/generate_test_data.py similarity index 100% rename from examples/test_data_gen/test_data_gen_local/construct_test_data_flow/generate_test_data.py rename to examples/test_data_gen/construct_test_data_flow/generate_test_data.py diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt b/examples/test_data_gen/construct_test_data_flow/requirements.txt similarity index 100% rename from examples/test_data_gen/test_data_gen_local/construct_test_data_flow/requirements.txt rename to examples/test_data_gen/construct_test_data_flow/requirements.txt diff --git a/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py b/examples/test_data_gen/construct_test_data_flow/utils.py similarity index 100% rename from examples/test_data_gen/test_data_gen_local/construct_test_data_flow/utils.py rename to examples/test_data_gen/construct_test_data_flow/utils.py diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini index 2f23422ec7e..c905b1ef6d1 100644 --- a/examples/test_data_gen/test_data_gen_local/config.ini +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -3,7 +3,7 @@ document_chunk_size = 1024 # cspell: ignore luyao document_nodes_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/document-nodes-test.jsonl" # test data gen flow configs -flow_folder = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/construct_test_data_flow" +flow_folder = "/Users/luyao/proj/promptflow/examples/test_data_gen/construct_test_data_flow" flow_batch_run_size = 10 # test data output path test_data_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/test_data" diff --git a/examples/test_data_gen/test_data_gen_pipeline/components.py b/examples/test_data_gen/test_data_gen_pipeline/components.py index 525680d5b85..aaf51fd319c 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/components.py +++ b/examples/test_data_gen/test_data_gen_pipeline/components.py @@ -82,7 +82,6 @@ def clean_test_data_set( print("reading file: %s ..." % test_data_set_path) with open(test_data_set_path, "r") as f: - print(f.read()) data = [json.loads(line) for line in f] # Filter out empty dictionaries diff --git a/examples/test_data_gen/test_data_gen_pipeline/config.ini b/examples/test_data_gen/test_data_gen_pipeline/config.ini index 50e080266d2..0d62c62ed37 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/config.ini +++ b/examples/test_data_gen/test_data_gen_pipeline/config.ini @@ -8,7 +8,7 @@ documents_folder = "/Users/luyao/proj/promptflow/docs/how-to-guides/develop-a-to doc_split_yml = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_pipeline/document_split.yml" document_chunk_size = 1024 # test data gen flow configs -flow_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/construct_test_data_flow/flow.dag.yaml" +flow_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml" # Parallel run step configs prs_instance_count = 2 prs_mini_batch_size = "100kb" From 236501564aff5eaef0e1db3c8e79536299cd3d66 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Wed, 17 Jan 2024 11:42:56 +0800 Subject: [PATCH 008/112] add data gen flow --- .../conditional_prompt.jinja2 | 18 + .../construct_test_data_flow/flow.dag.yaml | 200 +++++++---- .../generate_answer.py | 25 ++ .../generate_answer_prompt.jinja2 | 7 + .../generate_context.py | 29 ++ .../generate_context_prompt.jinja2 | 6 + .../generate_seed_question.py | 28 ++ .../generate_test_data.py | 51 --- .../generate_test_question.py | 35 ++ .../reasoning_prompt.jinja2 | 25 ++ .../construct_test_data_flow/requirements.txt | 5 - .../score_context_prompt.jinja2 | 5 + .../score_question_prompt.jinja2 | 7 + .../seed_question_prompt.jinja2 | 14 + .../construct_test_data_flow/utils.py | 310 ++++-------------- 15 files changed, 399 insertions(+), 366 deletions(-) create mode 100644 examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_answer.py create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_context.py create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_seed_question.py delete mode 100644 examples/test_data_gen/construct_test_data_flow/generate_test_data.py create mode 100644 examples/test_data_gen/construct_test_data_flow/generate_test_question.py create mode 100644 examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 delete mode 100644 examples/test_data_gen/construct_test_data_flow/requirements.txt create mode 100644 examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 create mode 100644 examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 new file mode 100644 index 00000000000..a7010f537b3 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/conditional_prompt.jinja2 @@ -0,0 +1,18 @@ +system: +Rewrite the provided question to increase its complexity by introducing a conditional element. +The goal is to make the question more intricate by incorporating a scenario or condition that affects the context of the question. +Follow the rules given below while rewriting the question. + 1. The rewritten question should not be longer than 25 words. Use abbreviation wherever possible. + 2. The rewritten question must be reasonable and must be understood and responded by humans. + 3. The rewritten question must be fully answerable from information present context. + 4. phrases like 'provided context','according to the context?',etc are not allowed to appear in the question. + +user: +for example, +question: What are the general principles for designing prompts in LLMs? +Rewritten Question:how to apply prompt designing principles to improve LLMs performance in reasoning tasks + +question: {{question}} +CONTEXTS: +{{context}} +Rewritten Question: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index e984071c6a2..90e6e324ddd 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -1,78 +1,144 @@ -$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json +id: template_standard_flow +name: Template Standard Flow environment: python_requirements_txt: requirements.txt inputs: - document_node: + text_chunk: type: string - default: '"{\"id_\": \"caf64060-1332-4069-b458-23152b2f2093\", \"embedding\": - null, \"metadata\": {\"file_path\": - \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", - \"file_name\": \"concept-connections.md\", \"file_type\": null, - \"file_size\": 2038, \"creation_date\": \"2024-01-11\", - \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": - \"2024-01-11\"}, \"excluded_embed_metadata_keys\": [\"file_name\", - \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", - \"last_accessed_date\"], \"excluded_llm_metadata_keys\": [\"file_name\", - \"file_type\", \"file_size\", \"creation_date\", \"last_modified_date\", - \"last_accessed_date\"], \"relationships\": {\"1\": {\"node_id\": - \"41017365-74a3-41fc-ae0c-ecf997eb768a\", \"node_type\": \"4\", - \"metadata\": {\"file_path\": - \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", - \"file_name\": \"concept-connections.md\", \"file_type\": null, - \"file_size\": 2038, \"creation_date\": \"2024-01-11\", - \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": - \"2024-01-11\"}, \"hash\": - \"68b4e587d4fbc41b04e006b2a50568b747ac3c39e381ee3135d4c14245a7f75d\", - \"class_name\": \"RelatedNodeInfo\"}, \"3\": {\"node_id\": - \"35b870cc-19e8-4f83-937a-4c387f759c01\", \"node_type\": \"1\", - \"metadata\": {\"file_path\": - \"D:\\\\proj\\\\PromptFlow\\\\src\\\\promptflow-copilot\\\\pfdocs\\\\community\\\\concepts\\\\concept-connections.md\", - \"file_name\": \"concept-connections.md\", \"file_type\": null, - \"file_size\": 2038, \"creation_date\": \"2024-01-11\", - \"last_modified_date\": \"2024-01-11\", \"last_accessed_date\": - \"2024-01-11\"}, \"hash\": - \"d114af44f58f5858fc28b8a6841f174556dfb07b3e1c6558b00337f34188d961\", - \"class_name\": \"RelatedNodeInfo\"}}, \"hash\": - \"05a40fabcdd62d0ebada83ce64eb84ce22e5942788f7d761b4028208a4313d4f\", - \"text\": \"Connections\\n\\nConnections are for storing information about - how to access external services like LLMs: endpoint, api keys etc.\\n\\n- - In your local development environment, the connections are persisted in - your local machine with keys encrypted.\\n- In Azure AI, connections can - be configured to be shared across the entire workspace. Secrets associated - with connections are securely persisted in the corresponding Azure Key - Vault, adhering to robust security and compliance standards.\\n\\nPrompt - flow provides a variety of pre-built connections, including Azure Open AI, - Open AI, etc. These pre-built connections enable seamless integration with - these resources within the built-in tools. Additionally, you have the - flexibility to create custom connection types using key-value pairs, - empowering them to tailor the connections to their specific requirements, - particularly in Python tools.\\n\\n| Connection - type | Built-in - tools |\\n| - ------------------------------------------------------------ | - ------------------------------- |\\n| Azure Open AI | LLM or - Python |\\n| Open AI | LLM - or Python |\\n| Cognitive Search | Vector DB Lookup or - Python |\\n| Serp | Serp API or - Python |\\n| - Custom | - Python |\\n\\nBy leveraging connections in prompt - flow, you can easily establish and manage connections to external APIs and - data sources, facilitating efficient data exchange and interaction within - their AI applications.\", \"start_char_idx\": null, \"end_char_idx\": - null, \"text_template\": \"{metadata_str}\\n\\n{content}\", - \"metadata_template\": \"{key}: {value}\", \"metadata_seperator\": - \"\\n\", \"class_name\": \"TextNode\"}"' + is_chat_input: false + default: >- + Adding a Tool Icon + + A tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package. + + + Adding a custom tool icon is optional. If you do not provide one, the system uses a default icon. outputs: - test_data: + question: type: string - reference: ${generate_test_data.output} + reference: ${generate_test_question.output.question} + answer: + type: string + reference: ${generate_answer.output} + context: + type: string + reference: ${generate_context.output} + question_type: + type: string + reference: ${generate_test_question.output.question_type} nodes: -- name: generate_test_data +- name: reasoning_prompt + type: prompt + source: + type: code + path: reasoning_prompt.jinja2 + inputs: + context: ${inputs.text_chunk} + question: ${generate_seed_question.output} + use_variants: false +- name: conditional_prompt + type: prompt + source: + type: code + path: conditional_prompt.jinja2 + inputs: + context: ${inputs.text_chunk} + question: ${generate_seed_question.output} + use_variants: false +- name: score_context_prompt + type: prompt + source: + type: code + path: score_context_prompt.jinja2 + inputs: + context: ${inputs.text_chunk} + use_variants: false +- name: score_seed_question_prompt + type: prompt + source: + type: code + path: score_question_prompt.jinja2 + inputs: + question: ${generate_seed_question.output} + use_variants: false +- name: seed_question_prompt + type: prompt + source: + type: code + path: seed_question_prompt.jinja2 + inputs: + context: ${inputs.text_chunk} + use_variants: false +- name: generate_context_prompt + type: prompt + source: + type: code + path: generate_context_prompt.jinja2 + inputs: + context: ${inputs.text_chunk} + question: ${generate_test_question.output.question} + use_variants: false +- name: generate_answer_prompt + type: prompt + source: + type: code + path: generate_answer_prompt.jinja2 + inputs: + context: ${generate_context.output} + question: ${generate_test_question.output} + use_variants: false +- name: generate_seed_question + type: python + source: + type: code + path: generate_seed_question.py + inputs: + connection: azure_openai_connection + model: gpt-35-turbo + score_context_prompt: ${score_context_prompt.output} + seed_question_prompt: ${seed_question_prompt.output} + use_variants: false +- name: generate_test_question + type: python + source: + type: code + path: generate_test_question.py + inputs: + connection: azure_openai_connection + conditional_prompt: ${conditional_prompt.output} + model: gpt-35-turbo + reasoning_prompt: ${reasoning_prompt.output} + score_seed_question_prompt: ${score_seed_question_prompt.output} + seed_question: ${generate_seed_question.output} + use_variants: false +- name: score_question_prompt + type: prompt + source: + type: code + path: score_question_prompt.jinja2 + inputs: + question: ${generate_test_question.output.question} + use_variants: false +- name: generate_context + type: python + source: + type: code + path: generate_context.py + inputs: + connection: azure_openai_connection + generate_context_prompt: ${generate_context_prompt.output} + model: gpt-35-turbo + question_info: ${generate_test_question.output} + score_question_prompt: ${score_question_prompt.output} + use_variants: false +- name: generate_answer type: python source: type: code - path: generate_test_data.py + path: generate_answer.py inputs: - connection: azure_open_ai_connection - document_node_str: ${inputs.document_node} + connection: azure_openai_connection + context: ${generate_context.output} + generate_answer_prompt: ${generate_answer_prompt.output} + model: gpt-35-turbo + use_variants: false diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer.py b/examples/test_data_gen/construct_test_data_flow/generate_answer.py new file mode 100644 index 00000000000..f853ff39639 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_answer.py @@ -0,0 +1,25 @@ +from typing import Union + +from utils import llm_call + +from promptflow import tool +from promptflow.connections import OpenAIConnection, AzureOpenAIConnection + + +@tool +def generate_answer( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + context: str, + generate_answer_prompt: str +): + """ + Generates a answer based on the given prompts and context information. + + Returns: + str: The generated answer. + """ + if context is None: + return None + + return llm_call(connection, model, generate_answer_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 new file mode 100644 index 00000000000..354cb63f293 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_answer_prompt.jinja2 @@ -0,0 +1,7 @@ +system: +Answer the question using the information from the given context. + +user: +question:{{question}} +context:{{context}} +answer: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context.py b/examples/test_data_gen/construct_test_data_flow/generate_context.py new file mode 100644 index 00000000000..398d0ca1ab5 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_context.py @@ -0,0 +1,29 @@ +from typing import Union + +from utils import llm_call, is_valid_question + +from promptflow import tool +from promptflow.connections import OpenAIConnection, AzureOpenAIConnection + + +@tool +def generate_context( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + question_info: dict, + generate_context_prompt: str, + score_question_prompt: str +): + """ + Generates a context based on the given prompts and question information. + + Returns: + str: The generated context. + """ + question = question_info["question"] + question_type = question_info["question_type"] + if question is None or ( + question_type != "simple" and not is_valid_question(connection, model, score_question_prompt)): + return None + + return llm_call(connection, model, generate_context_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 new file mode 100644 index 00000000000..9c21369c647 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_context_prompt.jinja2 @@ -0,0 +1,6 @@ +system: +Please extract relevant sentences from the provided context that can potentially help answer the following question. While extracting candidate sentences you're not allowed to make any changes to sentences from given context. + +user: +question:{{question}} +context:{{context}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py b/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py new file mode 100644 index 00000000000..5977f14f5bf --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py @@ -0,0 +1,28 @@ +from typing import Union + +from utils import llm_call + +from promptflow import tool +from promptflow.connections import OpenAIConnection, AzureOpenAIConnection + + +@tool +def generate_seed_question( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + score_context_prompt: str, + seed_question_prompt: str +): + """ + Generates a seed question based on the given prompts. + + Returns: + str: The generated seed question. + """ + context_filter = llm_call(connection, model, score_context_prompt) + if not context_filter: + print("invalid context.") + return None + + seed_question = llm_call(connection, model, seed_question_prompt) + return seed_question diff --git a/examples/test_data_gen/construct_test_data_flow/generate_test_data.py b/examples/test_data_gen/construct_test_data_flow/generate_test_data.py deleted file mode 100644 index d7026d7ae56..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/generate_test_data.py +++ /dev/null @@ -1,51 +0,0 @@ -import os - -from langchain.chat_models import AzureChatOpenAI -from langchain.embeddings import AzureOpenAIEmbeddings -from llama_index.schema import TextNode -from ragas.llms import LangchainLLM -from utils import TestsetGeneratorV2 - -from promptflow import tool -from promptflow.connections import AzureOpenAIConnection - - -# The inputs section will change based on the arguments of the tool function, after you save the code -# Adding type to arguments and return value will help the system show the types properly -# Please update the function name/signature per need -@tool -def my_python_tool(connection: AzureOpenAIConnection, document_node_str: str) -> dict: - - os.environ["AZURE_OPENAI_API_KEY"] = connection.api_key - os.environ["AZURE_OPENAI_ENDPOINT"] = connection.api_base - os.environ["OPENAI_API_VERSION"] = connection.api_version - - azure_model = AzureChatOpenAI(deployment_name="gpt-4", model="gpt-4") - - azure_embeddings = AzureOpenAIEmbeddings(deployment="text-embedding-ada-002", model="text-embedding-ada-002") - - generator_llm = LangchainLLM(llm=azure_model) - critic_llm = LangchainLLM(llm=azure_model) - embeddings_model = azure_embeddings - - testset_distribution = { - "simple": 1, - "reasoning": 0, - "multi_context": 0, - "conditional": 0, - } - - test_generator = TestsetGeneratorV2( - generator_llm=generator_llm, - critic_llm=critic_llm, - embeddings_model=embeddings_model, - testset_distribution=testset_distribution, - chat_qa=0, - ) - - # json_dict = json.dumps(document_node_str) - document_node = TextNode.from_json(document_node_str) - - test_data = test_generator.generate(document_node=document_node) - - return test_data diff --git a/examples/test_data_gen/construct_test_data_flow/generate_test_question.py b/examples/test_data_gen/construct_test_data_flow/generate_test_question.py new file mode 100644 index 00000000000..973ee68e3a4 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/generate_test_question.py @@ -0,0 +1,35 @@ +from typing import Union + +from utils import is_valid_question, validate_distribution, get_question_type, generate_question + +from promptflow import tool +from promptflow.connections import OpenAIConnection, AzureOpenAIConnection + + +@tool +def generate_test_question( + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + seed_question: str, + reasoning_prompt: str, + conditional_prompt: str, + score_seed_question_prompt: str, + simple_ratio: float = 0.5, + reasoning_ratio: float = 0.25, + conditional_ratio: float = 0.25 +): + """ + Generates a test question based on the given prompts and distribution ratios. + + Returns: + dict: The generated test question and its type. + """ + if seed_question is None or not is_valid_question(connection, model, score_seed_question_prompt): + return None + + testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) + + question_type = get_question_type(testset_distribution) + question = generate_question(connection, model, question_type, seed_question, reasoning_prompt, conditional_prompt) + + return {"question": question, "question_type": question_type} diff --git a/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 new file mode 100644 index 00000000000..f53a8bc2e72 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/reasoning_prompt.jinja2 @@ -0,0 +1,25 @@ +system: +You are a prompt rewriter. You will be provided with a question and a long context.Your task to is to complicate the given question to improve the difficulty of answering. +You should do complicate the question by rewriting question into a multi-hop reasoning question based on the provided context. The question should require the reader to make multiple logical connections or inferences using the information available in given context. +Here are some strategies to create multi-hop questions: + + - Bridge related entities: Identify information that relates specific entities and frame question that can be answered only by analysing information of both entities. + + - Use Pronouns: identify (he, she, it, they) that refer to same entity or concepts in the context, and ask questions that would require the reader to figure out what pronouns refer to. + + - Refer to Specific Details: Mention specific details or facts from different parts of the context including tables, code, etc and ask how they are related. + + - Pose Hypothetical Scenarios: Present a hypothetical situation or scenario that requires combining different elements from the context to arrive at an answer. + +Rules to follow when rewriting question: +1. Ensure that the rewritten question can be answered entirely from the information present in the contexts. +2. Do not frame questions that contains more than 15 words. Use abbreviation wherever possible. +3. Make sure the question is clear and unambiguous. +4. phrases like 'based on the provided context','according to the context',etc are not allowed to appear in the question. + +user: +question: {{question}} +CONTEXTS: +{{context}} + +Multi-hop Reasoning Question: \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/requirements.txt b/examples/test_data_gen/construct_test_data_flow/requirements.txt deleted file mode 100644 index 65274d176b2..00000000000 --- a/examples/test_data_gen/construct_test_data_flow/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -promptflow[azure] -python-dotenv -bs4 -llama_index -ragas==0.0.21 diff --git a/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 new file mode 100644 index 00000000000..7e4804a1606 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 @@ -0,0 +1,5 @@ +system: +Checks if the context is has information worthy of framing a question, return true or false. + +user: +context: {{context}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 new file mode 100644 index 00000000000..e341b81794e --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 @@ -0,0 +1,7 @@ +system: +Determine if the given question can be clearly understood even when presented without any additional context. Specify reason and verdict is a valid json format. + +user: +question: What is the keyword that best describes the paper's focus in natural language understanding tasks? +{"reason":"The specific paper being referred to is not mentioned in the question.", "verdict": "No"} +question:{{question}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 new file mode 100644 index 00000000000..9278e3a35f3 --- /dev/null +++ b/examples/test_data_gen/construct_test_data_flow/seed_question_prompt.jinja2 @@ -0,0 +1,14 @@ +system: +Your task is to formulate a question from given context satisfying the rules given below: +1.The question should make sense to humans even when read without the given context. +2.The question should be fully answered from the given context. +3.The question should be framed from a part of context that contains important information. It can also be from tables,code,etc. +4.The answer to the question should not contain any links. +5.The question should be of moderate difficulty. +6.The question must be reasonable and must be understood and responded by humans. +7.Do no use phrases like 'provided context',etc in the question +8.Avoid framing question using word "and" that can be decomposed into more than one question. +9.The question should not contain more than 10 words, make of use of abbreviation wherever possible. + +user: +context: {{context}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/utils.py b/examples/test_data_gen/construct_test_data_flow/utils.py index 24c14f28b1d..0d99389ba58 100644 --- a/examples/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/construct_test_data_flow/utils.py @@ -1,250 +1,74 @@ -from __future__ import annotations - -import typing as t -import warnings -from collections import defaultdict - -try: - from llama_index.schema import BaseNode -except ImportError: - raise ImportError( - "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." - ) +import json +import re import numpy as np import numpy.testing as npt -from langchain.embeddings import OpenAIEmbeddings -from langchain.embeddings.base import Embeddings -from langchain.prompts import ChatPromptTemplate +import openai from numpy.random import default_rng -from ragas.llms import llm_factory -from ragas.testset.prompts import ( - ANSWER_FORMULATE, - COMPRESS_QUESTION, - CONDITIONAL_QUESTION, - CONTEXT_FORMULATE, - CONVERSATION_QUESTION, - FILTER_QUESTION, - MULTICONTEXT_QUESTION, - REASONING_QUESTION, - SCORE_CONTEXT, - SEED_QUESTION, -) -from ragas.testset.utils import load_as_json, load_as_score - -if t.TYPE_CHECKING: - from ragas.llms.base import RagasLLM - - -DEFAULT_TEST_DISTRIBUTION = { - "simple": 0.4, - "reasoning": 0.2, - "multi_context": 0.2, - "conditional": 0.2, -} - - -class TestsetGeneratorV2: +from promptflow.connections import OpenAIConnection, AzureOpenAIConnection + + +def parse_chat(prompt): + messages = [{'role': role, 'content': content.strip()} for role, content in + re.findall(r'(system|user):(.*?)$', prompt, re.DOTALL)] + return messages + + +def llm_call(connection, model, prompt): + client = get_client_by_connection_type(connection) + messages = parse_chat(prompt) + return client.chat.completions.create(model=model, messages=messages).choices[0].message.content + + +def get_client_by_connection_type(connection): + if isinstance(connection, AzureOpenAIConnection): + return openai.AzureOpenAI(api_key=connection.api_key, api_version=connection.api_version, + azure_endpoint=connection.api_base) + elif isinstance(connection, OpenAIConnection): + return openai.OpenAI(api_key=connection.api_key, base_url=connection.base_url, + organization=connection.organization) + + +def get_question_type(testset_distribution) -> str: """ - Ragas Test Set Generator - - Attributes - ---------- - generator_llm: LangchainLLM - LLM used for all the generator operations in the TestGeneration paradigm. - critique_llm: LangchainLLM - LLM used for all the filtering and scoring operations in TestGeneration - paradigm. - embeddings_model: Embeddings - Embeddings used for vectorizing nodes when required. - chat_qa: float - Determines the fraction of conversational questions the resulting test set. - chunk_size: int - The chunk size of nodes created from data. - test_distribution : dict - Distribution of different types of questions to be generated from given - set of documents. Defaults to {"easy":0.1, "reasoning":0.4, "conversation":0.5} + Decides question evolution type based on probability """ - - def __init__( - self, - generator_llm: RagasLLM, - critic_llm: RagasLLM, - embeddings_model: Embeddings, - testset_distribution: t.Optional[t.Dict[str, float]] = None, - chat_qa: float = 0.0, - chunk_size: int = 1024, - seed: int = 42, - ) -> None: - self.generator_llm = generator_llm - self.critic_llm = critic_llm - self.embedding_model = embeddings_model - testset_distribution = testset_distribution or DEFAULT_TEST_DISTRIBUTION - npt.assert_almost_equal( - 1, - sum(testset_distribution.values()), - err_msg="Sum of distribution should be 1", - ) - - prob = np.cumsum(list(testset_distribution.values())) - types = testset_distribution.keys() - self.testset_distribution = dict(zip(types, prob)) - - self.chat_qa = chat_qa - self.chunk_size = chunk_size - self.threshold = 7.5 - self.rng = default_rng(seed) - - @classmethod - def from_default( - cls, - openai_generator_llm: str = "gpt-3.5-turbo-16k", - openai_filter_llm: str = "gpt-4", - chat_qa: float = 0.3, - chunk_size: int = 512, - testset_distribution: dict = DEFAULT_TEST_DISTRIBUTION, - ): - generator_llm = llm_factory(openai_generator_llm) - critic_llm = llm_factory(openai_filter_llm) - embeddings_model = OpenAIEmbeddings() # type: ignore - return cls( - generator_llm=generator_llm, - critic_llm=critic_llm, - embeddings_model=embeddings_model, - chat_qa=chat_qa, - chunk_size=chunk_size, - testset_distribution=testset_distribution, - ) - - def _get_evolve_type(self) -> str: - """ - Decides question evolution type based on probability - """ - prob = self.rng.uniform(0, 1) - print("yao-debug: evolve type prob:", prob) - return next( - (key for key in self.testset_distribution.keys() if prob <= self.testset_distribution[key]), - "simple", - ) - - def _filter_context(self, context: str) -> bool: - """ - context: str - The input context - - Checks if the context is has information worthy of framing a question - """ - human_prompt = SCORE_CONTEXT.format(context=context) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - results = self.critic_llm.generate(prompts=[prompt]) - output = results.generations[0][0].text.strip() - score = load_as_score(output) - return score >= self.threshold - - def _seed_question(self, context: str) -> str: - human_prompt = SEED_QUESTION.format(context=context) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - results = self.generator_llm.generate(prompts=[prompt]) - return results.generations[0][0].text.strip() - - def _filter_question(self, question: str) -> bool: - human_prompt = FILTER_QUESTION.format(question=question) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - - results = self.critic_llm.generate(prompts=[prompt]) - results = results.generations[0][0].text.strip() - json_results = load_as_json(results) - return json_results.get("verdict") != "No" - - def _reasoning_question(self, question: str, context: str) -> str: - return self._qc_template(REASONING_QUESTION, question, context) - - def _condition_question(self, question: str, context: str) -> str: - return self._qc_template(CONDITIONAL_QUESTION, question, context) - - def _multicontext_question(self, question: str, context1: str, context2: str) -> str: - human_prompt = MULTICONTEXT_QUESTION.format(question=question, context1=context1, context2=context2) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - results = self.generator_llm.generate(prompts=[prompt]) - return results.generations[0][0].text.strip() - - def _compress_question(self, question: str) -> str: - return self._question_transformation(COMPRESS_QUESTION, question=question) - - def _conversational_question(self, question: str) -> str: - return self._question_transformation(CONVERSATION_QUESTION, question=question) - - def _question_transformation(self, prompt, question: str) -> str: - human_prompt = prompt.format(question=question) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - results = self.generator_llm.generate(prompts=[prompt]) - return results.generations[0][0].text.strip() - - def _qc_template(self, prompt, question, context) -> str: - human_prompt = prompt.format(question=question, context=context) - prompt = ChatPromptTemplate.from_messages([human_prompt]) - results = self.generator_llm.generate(prompts=[prompt]) - return results.generations[0][0].text.strip() - - def _generate_answer(self, question: str, context: t.List[str]) -> t.List[str]: - return [self._qc_template(ANSWER_FORMULATE, ques, context[i]) for i, ques in enumerate(question.split("\n"))] - - def _generate_context(self, question: str, text_chunk: str) -> t.List[str]: - return [self._qc_template(CONTEXT_FORMULATE, ques, text_chunk) for ques in question.split("\n")] - - def _remove_nodes(self, available_indices: t.List[BaseNode], node_idx: t.List) -> t.List[BaseNode]: - for idx in node_idx: - available_indices.remove(idx) - return available_indices - - def _generate_doc_nodes_map(self, document_nodes: t.List[BaseNode]) -> t.Dict[str, t.List[BaseNode]]: - doc_nodes_map: t.Dict[str, t.List[BaseNode]] = defaultdict(list) - for node in document_nodes: - if node.ref_doc_id: - doc_nodes_map[node.ref_doc_id].append(node) - - return doc_nodes_map # type: ignore - - def _get_neighbour_node(self, node: BaseNode, related_nodes: t.List[BaseNode]) -> t.List[BaseNode]: - if len(related_nodes) < 2: - warnings.warn("No neighbors exists") - return [node] - idx = related_nodes.index(node) - ids = [idx - 1, idx] if idx == (len(related_nodes) - 1) else [idx, idx + 1] - return [related_nodes[idx] for idx in ids] - - def _embed_nodes(self, nodes: t.List[BaseNode]) -> t.Dict[str, t.List[float]]: - embeddings = {} - for node in nodes: - embeddings[node.id_] = list(self.embedding_model.embed_query(node.get_content())) - - return embeddings - - def generate( - self, - document_node: BaseNode, - ) -> dict: - text_chunk = document_node.get_content() - score = self._filter_context(text_chunk) - if not score: - print("Failed to validate context.") - return {} - seed_question = self._seed_question(text_chunk) - # is_valid_question = self._filter_question(seed_question) - # if not is_valid_question: - # print("The seed question is not valid.") - # return {} - - question = seed_question - context = self._generate_context(question, text_chunk) - answer = self._generate_answer(question, context) - for i, (ques, ctx, ans) in enumerate(zip(question.split("\n"), context, answer)): - my_data_row = { - "question": ques, - "ground_truth_context": ctx, - "ground_truth": ans, - "question_type": "simple", - } - - return my_data_row + rng = default_rng() + prob = rng.uniform(0, 1) + return next( + ( + key + for key in testset_distribution.keys() + if prob <= testset_distribution[key] + ), + "simple") + + +def is_valid_question(connection, model, prompt): + is_valid = json.loads(llm_call(connection, model, prompt))["verdict"] != "No" + if not is_valid: + print("Invalid question.") + return is_valid + + +def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): + testset_distribution = { + "simple": simple_ratio, + "reasoning": reasoning_ratio, + "conditional": conditional_ratio, + } + npt.assert_almost_equal(1, sum(testset_distribution.values()), err_msg="Sum of distribution should be 1") + testset_distribution = dict(zip(testset_distribution.keys(), np.cumsum(list(testset_distribution.values())))) + return testset_distribution + + +def generate_question(connection, model, question_type, seed_question, reasoning_prompt, conditional_prompt): + if question_type == "simple": + return seed_question + elif question_type == "reasoning": + return llm_call(connection, model, reasoning_prompt) + elif question_type == "conditional": + return llm_call(connection, model, conditional_prompt) + else: + raise Exception("Invalid question type.") From 740670e665b3c78f7174fa8473c7288104165dba Mon Sep 17 00:00:00 2001 From: yalu4 Date: Thu, 18 Jan 2024 10:02:09 +0800 Subject: [PATCH 009/112] fix bug and update --- docs/how-to-guides/construct-test-data.md | 23 +++++- .../construct_test_data_flow/flow.dag.yaml | 27 ++++--- .../generate_answer.py | 19 ++--- .../generate_context.py | 33 ++++---- .../generate_seed_question.py | 24 +++--- .../generate_test_question.py | 38 ++++----- .../construct_test_data_flow/requirements.txt | 0 ....jinja2 => validate_context_prompt.jinja2} | 2 +- ...jinja2 => validate_question_prompt.jinja2} | 2 +- examples/test_data_gen/contants.py | 2 + .../test_data_gen_local/config.ini | 9 ++- .../test_data_gen_local/doc_split.py | 13 ++- .../test_data_gen_local/run_test_data_gen.py | 80 ++++++++++++++----- .../test_data_gen_pipeline/config.ini | 7 +- .../test_data_gen_pipeline/requirements.txt | 2 + .../run_test_data_gen_pipeline.py | 67 +++++++++++----- 16 files changed, 219 insertions(+), 129 deletions(-) create mode 100644 examples/test_data_gen/construct_test_data_flow/requirements.txt rename examples/test_data_gen/construct_test_data_flow/{score_context_prompt.jinja2 => validate_context_prompt.jinja2} (83%) rename examples/test_data_gen/construct_test_data_flow/{score_question_prompt.jinja2 => validate_question_prompt.jinja2} (94%) create mode 100644 examples/test_data_gen/contants.py create mode 100644 examples/test_data_gen/test_data_gen_pipeline/requirements.txt diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index 90b4198205a..7c012d48042 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -2,7 +2,26 @@ ## Data preprocess -### local +### Local +#### Prerequisites +Enter `test_data_gen_local` folder, run below command to install required packages. +```bash +pip install -r requirements.txt +``` + +#### Get started + +### Cloud +#### Prerequisites +Enter `test_data_gen_pipeline` folder, run below command to install required packages. +```bash +pip install -r requirements.txt +``` + +#### Get started +- Fill in the config values in `config.in` + +## Appendix Run doc_split script. Interface: - documents folder path @@ -17,7 +36,7 @@ Interface: In this sample script, the `SimpleDirectoryReader` of llamaindex is used to split the documents into smaller granularity. For more supported file types, please check [here](https://docs.llamaindex.ai/en/stable/module_guides/loading/simpledirectoryreader.html). more file readers: ?? -### portal + Locally run doc_split script. Then upload the generated doc nodes jsonl file to portal as a data asset. -> In this way, we should at least consider how user can do both process in local and cloud. local: read folder from remote site, then upload to cloud. diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index 90e6e324ddd..34a64d1337f 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -1,3 +1,4 @@ +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json id: template_standard_flow name: Template Standard Flow environment: @@ -45,19 +46,19 @@ nodes: context: ${inputs.text_chunk} question: ${generate_seed_question.output} use_variants: false -- name: score_context_prompt +- name: validate_context_prompt type: prompt source: type: code - path: score_context_prompt.jinja2 + path: validate_context_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false -- name: score_seed_question_prompt +- name: validate_seed_question_prompt type: prompt source: type: code - path: score_question_prompt.jinja2 + path: validate_question_prompt.jinja2 inputs: question: ${generate_seed_question.output} use_variants: false @@ -93,9 +94,9 @@ nodes: type: code path: generate_seed_question.py inputs: - connection: azure_openai_connection + connection: azure_open_ai_connection model: gpt-35-turbo - score_context_prompt: ${score_context_prompt.output} + validate_context_prompt: ${validate_context_prompt.output} seed_question_prompt: ${seed_question_prompt.output} use_variants: false - name: generate_test_question @@ -104,18 +105,18 @@ nodes: type: code path: generate_test_question.py inputs: - connection: azure_openai_connection + connection: azure_open_ai_connection conditional_prompt: ${conditional_prompt.output} model: gpt-35-turbo reasoning_prompt: ${reasoning_prompt.output} - score_seed_question_prompt: ${score_seed_question_prompt.output} + validate_seed_question_prompt: ${validate_seed_question_prompt.output} seed_question: ${generate_seed_question.output} use_variants: false -- name: score_question_prompt +- name: validate_question_prompt type: prompt source: type: code - path: score_question_prompt.jinja2 + path: validate_question_prompt.jinja2 inputs: question: ${generate_test_question.output.question} use_variants: false @@ -125,11 +126,11 @@ nodes: type: code path: generate_context.py inputs: - connection: azure_openai_connection + connection: azure_open_ai_connection generate_context_prompt: ${generate_context_prompt.output} model: gpt-35-turbo question_info: ${generate_test_question.output} - score_question_prompt: ${score_question_prompt.output} + validate_question_prompt: ${validate_question_prompt.output} use_variants: false - name: generate_answer type: python @@ -137,7 +138,7 @@ nodes: type: code path: generate_answer.py inputs: - connection: azure_openai_connection + connection: azure_open_ai_connection context: ${generate_context.output} generate_answer_prompt: ${generate_answer_prompt.output} model: gpt-35-turbo diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer.py b/examples/test_data_gen/construct_test_data_flow/generate_answer.py index f853ff39639..13ec7a3e3af 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_answer.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_answer.py @@ -3,23 +3,20 @@ from utils import llm_call from promptflow import tool -from promptflow.connections import OpenAIConnection, AzureOpenAIConnection +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool def generate_answer( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - context: str, - generate_answer_prompt: str + connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, context: str, generate_answer_prompt: str ): - """ - Generates a answer based on the given prompts and context information. + """ + Generates a answer based on the given prompts and context information. - Returns: - str: The generated answer. + Returns: + str: The generated answer. """ - if context is None: - return None + if not context: + return "" return llm_call(connection, model, generate_answer_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context.py b/examples/test_data_gen/construct_test_data_flow/generate_context.py index 398d0ca1ab5..377ffd3070d 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_context.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_context.py @@ -1,29 +1,32 @@ from typing import Union -from utils import llm_call, is_valid_question +from utils import is_valid_question, llm_call from promptflow import tool -from promptflow.connections import OpenAIConnection, AzureOpenAIConnection +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool def generate_context( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - question_info: dict, - generate_context_prompt: str, - score_question_prompt: str -): - """ - Generates a context based on the given prompts and question information. + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + question_info: dict, + generate_context_prompt: str, + validate_question_prompt: str, +) -> str: + """ + Generates a context based on the given prompts and question information. - Returns: - str: The generated context. + Returns: + str: The generated context. """ + if not question_info: + return "" question = question_info["question"] question_type = question_info["question_type"] - if question is None or ( - question_type != "simple" and not is_valid_question(connection, model, score_question_prompt)): - return None + if not question or ( + question_type != "simple" and not is_valid_question(connection, model, validate_question_prompt) + ): + return "" return llm_call(connection, model, generate_context_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py b/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py index 5977f14f5bf..8b69a923ac0 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py @@ -3,26 +3,26 @@ from utils import llm_call from promptflow import tool -from promptflow.connections import OpenAIConnection, AzureOpenAIConnection +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool def generate_seed_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - score_context_prompt: str, - seed_question_prompt: str + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + validate_context_prompt: str, + seed_question_prompt: str, ): - """ - Generates a seed question based on the given prompts. - - Returns: - str: The generated seed question. """ - context_filter = llm_call(connection, model, score_context_prompt) + Generates a seed question based on the given prompts. + + Returns: + str: The generated seed question. + """ + context_filter = llm_call(connection, model, validate_context_prompt) if not context_filter: print("invalid context.") - return None + return "" seed_question = llm_call(connection, model, seed_question_prompt) return seed_question diff --git a/examples/test_data_gen/construct_test_data_flow/generate_test_question.py b/examples/test_data_gen/construct_test_data_flow/generate_test_question.py index 973ee68e3a4..5698e00df10 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_test_question.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_test_question.py @@ -1,31 +1,31 @@ from typing import Union -from utils import is_valid_question, validate_distribution, get_question_type, generate_question +from utils import generate_question, get_question_type, is_valid_question, validate_distribution from promptflow import tool -from promptflow.connections import OpenAIConnection, AzureOpenAIConnection +from promptflow.connections import AzureOpenAIConnection, OpenAIConnection @tool def generate_test_question( - connection: Union[OpenAIConnection, AzureOpenAIConnection], - model: str, - seed_question: str, - reasoning_prompt: str, - conditional_prompt: str, - score_seed_question_prompt: str, - simple_ratio: float = 0.5, - reasoning_ratio: float = 0.25, - conditional_ratio: float = 0.25 -): - """ - Generates a test question based on the given prompts and distribution ratios. - - Returns: - dict: The generated test question and its type. + connection: Union[OpenAIConnection, AzureOpenAIConnection], + model: str, + seed_question: str, + reasoning_prompt: str, + conditional_prompt: str, + validate_seed_question_prompt: str, + simple_ratio: float = 0.5, + reasoning_ratio: float = 0.25, + conditional_ratio: float = 0.25, +) -> dict: """ - if seed_question is None or not is_valid_question(connection, model, score_seed_question_prompt): - return None + Generates a test question based on the given prompts and distribution ratios. + + Returns: + dict: The generated test question and its type. + """ + if not seed_question or not is_valid_question(connection, model, validate_seed_question_prompt): + return {"question": "", "question_type": ""} testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) diff --git a/examples/test_data_gen/construct_test_data_flow/requirements.txt b/examples/test_data_gen/construct_test_data_flow/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 similarity index 83% rename from examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 rename to examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 index 7e4804a1606..32f55eb7e8e 100644 --- a/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 @@ -2,4 +2,4 @@ system: Checks if the context is has information worthy of framing a question, return true or false. user: -context: {{context}} \ No newline at end of file +context: {{context}} diff --git a/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 similarity index 94% rename from examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 rename to examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 index e341b81794e..f5c701353b7 100644 --- a/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 @@ -4,4 +4,4 @@ Determine if the given question can be clearly understood even when presented wi user: question: What is the keyword that best describes the paper's focus in natural language understanding tasks? {"reason":"The specific paper being referred to is not mentioned in the question.", "verdict": "No"} -question:{{question}} \ No newline at end of file +question:{{question}} diff --git a/examples/test_data_gen/contants.py b/examples/test_data_gen/contants.py new file mode 100644 index 00000000000..e3e6d1de170 --- /dev/null +++ b/examples/test_data_gen/contants.py @@ -0,0 +1,2 @@ +DOCUMENT_NODE = "document_node" +TEXT_CHUNK = "text_chunk" diff --git a/examples/test_data_gen/test_data_gen_local/config.ini b/examples/test_data_gen/test_data_gen_local/config.ini index c905b1ef6d1..08aa3e8b698 100644 --- a/examples/test_data_gen/test_data_gen_local/config.ini +++ b/examples/test_data_gen/test_data_gen_local/config.ini @@ -1,9 +1,10 @@ -documents_folder = "" +should_skip_doc_split = True +documents_folder = "D:\proj\github\ms\promptflow\docs\how-to-guides" document_chunk_size = 1024 # cspell: ignore luyao -document_nodes_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/document-nodes-test.jsonl" +document_nodes_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\document-nodes-test.jsonl" # test data gen flow configs -flow_folder = "/Users/luyao/proj/promptflow/examples/test_data_gen/construct_test_data_flow" +flow_folder = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow" flow_batch_run_size = 10 # test data output path -test_data_output_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_local/test_data" +test_data_output_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\test_data" diff --git a/examples/test_data_gen/test_data_gen_local/doc_split.py b/examples/test_data_gen/test_data_gen_local/doc_split.py index ff8e4ca90df..b2bfe273757 100644 --- a/examples/test_data_gen/test_data_gen_local/doc_split.py +++ b/examples/test_data_gen/test_data_gen_local/doc_split.py @@ -1,8 +1,8 @@ import argparse import json import os +import sys import typing as t -from datetime import datetime from llama_index import SimpleDirectoryReader from llama_index.readers import BeautifulSoupWebReader @@ -16,6 +16,9 @@ "llama_index must be installed to use this function. " "Please, install it with `pip install llama_index`." ) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +from contants import DOCUMENT_NODE, TEXT_CHUNK # noqa: E402 + def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, urls: list = None): # load docs @@ -26,9 +29,6 @@ def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, url documents_folder, recursive=True, exclude=["index.md", "README.md"], encoding="utf-8" ).load_data() - doc_info = [doc.metadata["file_name"] for doc in documents] - print(f"documents: {doc_info}") - # Convert documents into nodes node_parser = SentenceSplitter.from_defaults(chunk_size=chunk_size, chunk_overlap=0, include_metadata=True) documents = t.cast(t.List[LlamaindexDocument], documents) @@ -36,11 +36,10 @@ def split_doc(documents_folder: str, output_file_path: str, chunk_size: int, url jsonl_str = "" for doc in document_nodes: - json_dict = {"document_node": doc.to_json()} + json_dict = {TEXT_CHUNK: doc.text, DOCUMENT_NODE: doc.to_json()} jsonl_str += json.dumps(json_dict) + "\n" - cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") - with open(os.path.join(output_file_path, "document-nodes-" + cur_time_str + ".jsonl"), "wt") as text_file: + with open(output_file_path, "wt") as text_file: print(f"{jsonl_str}", file=text_file) diff --git a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py index e1622ef36e6..0f14ea13d5b 100644 --- a/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py +++ b/examples/test_data_gen/test_data_gen_local/run_test_data_gen.py @@ -1,14 +1,27 @@ import json import os +import sys from datetime import datetime import configargparse +from doc_split import split_doc from promptflow import PFClient from promptflow.entities import Run +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +from contants import TEXT_CHUNK # noqa: E402 -def batch_run_flow(pf: PFClient, flow_folder: str, flow_input_data: str, flow_batch_run_size: int): +CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) + + +def batch_run_flow( + pf: PFClient, + flow_folder: str, + flow_input_data: str, + flow_batch_run_size: int, + connection_name: str = "azure_open_ai_connection", +): environment_variables = { "PF_WORKER_COUNT": str(flow_batch_run_size), "PF_BATCH_METHOD": "spawn", @@ -21,7 +34,13 @@ def batch_run_flow(pf: PFClient, flow_folder: str, flow_input_data: str, flow_ba data=flow_input_data, stream=True, # TODO: understand 'stream' environment_variables=environment_variables, - column_mapping={"document_node": "${data.document_node}"}, + connections={ + "generate_seed_question": {"connection": connection_name}, + "generate_test_question": {"connection": connection_name}, + "generate_context": {"connection": connection_name}, + "generate_answer": {"connection": connection_name}, + }, + column_mapping={TEXT_CHUNK: "${data.text_chunk}"}, debug=True, ) @@ -29,42 +48,65 @@ def batch_run_flow(pf: PFClient, flow_folder: str, flow_input_data: str, flow_ba def get_batch_run_output(pf: PFClient, base_run: Run): - print("start to get batch flow run details.") + print(f"Start to get batch run {base_run} details.") # get run output details = pf.get_details(base_run) # TODO: error handling like if the run failed because of rate limit. - return details["outputs.test_data"].tolist() + question = details["outputs.question"].tolist() + answer = details["outputs.answer"].tolist() + context = details["outputs.context"].tolist() + question_type = details["outputs.question_type"].tolist() + return [ + {"question": q, "answer": a, "context": c, "question_type": qt} + for q, a, c, qt in zip(question, answer, context, question_type) + ] -def get_cleaned_data_and_save(test_data_set: list, test_data_output_path: str): - cleaned_data = [test_data for test_data in test_data_set if test_data] +def clean_data_and_save(test_data_set: list, test_data_output_path: str): + cleaned_data = [test_data for test_data in test_data_set if test_data and all(val for val in test_data.values())] jsonl_str = "\n".join(map(json.dumps, cleaned_data)) cur_time_str = datetime.now().strftime("%b-%d-%Y-%H-%M-%S") - with open(os.path.join(test_data_output_path, "file-" + cur_time_str + ".jsonl"), "wt") as text_file: + with open(os.path.join(test_data_output_path, "test-data-" + cur_time_str + ".jsonl"), "wt") as text_file: print(f"{jsonl_str}", file=text_file) if __name__ == "__main__": - parser = configargparse.ArgParser(default_config_files=["./config.ini"]) - parser.add("--documents_folder", required=True, help="Documents folder path") - parser.add("--document_chunk_size", required=False, help="Document chunk size, default is 1024") - parser.add("--document_nodes_output_path", required=False, help="Document nodes output path, default is ./") - parser.add("--flow_folder", required=True, help="Test data generation flow folder path") - parser.add("--flow_batch_run_size", required=False, help="Test data generation flow batch run size, default is 16") - parser.add("--test_data_output_path", required=True, help="Test data output path.") + if os.path.isfile(CONFIG_FILE): + parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + else: + raise Exception( + f"'{CONFIG_FILE}' does not exist. " + + "Please check if you are under the wrong directory or the file is missing." + ) + parser.add("--should_skip_doc_split", action="store_true", help="Skip doc split or not") + parser.add("--documents_folder", required=False, type=str, help="Documents folder path") + parser.add("--document_chunk_size", required=False, type=int, help="Document chunk size, default is 1024") + parser.add( + "--document_nodes_output_path", required=False, type=str, help="Document nodes output path, default is ./" + ) + parser.add("--flow_folder", required=True, type=str, help="Test data generation flow folder path") + parser.add( + "--flow_batch_run_size", + required=False, + type=int, + help="Test data generation flow batch run size, default is 16", + ) + parser.add("--test_data_output_path", required=True, type=str, help="Test data output path.") args = parser.parse_args() + if not (args.documents_folder or args.document_nodes_output_path): + parser.error("Either 'documents_folder' or 'document_nodes_output_path' should be specified.") + + # check_file_path_exists(args.test_data_output_path) + if not args.should_skip_doc_split: + split_doc(args.documents_folder, args.document_nodes_output_path, args.document_chunk_size) pf = PFClient() # TODO: error handling - print( - f"yao-debug: flow_folder: {args.flow_folder}, document_nodes_output_path: {args.document_nodes_output_path}", - f"flow_batch_run_size: {args.flow_batch_run_size}\n", - ) batch_run = batch_run_flow(pf, args.flow_folder, args.document_nodes_output_path, args.flow_batch_run_size) test_data_set = get_batch_run_output(pf, batch_run) - get_cleaned_data_and_save(test_data_set, args.test_data_output_path) + clean_data_and_save(test_data_set, args.test_data_output_path) diff --git a/examples/test_data_gen/test_data_gen_pipeline/config.ini b/examples/test_data_gen/test_data_gen_pipeline/config.ini index 0d62c62ed37..9d45772604c 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/config.ini +++ b/examples/test_data_gen/test_data_gen_pipeline/config.ini @@ -4,14 +4,11 @@ resource_group = "promptflow" workspace_name = "yaopfeus" aml_cluster = "cpu-cluster" # cspell: ignore luyao -documents_folder = "/Users/luyao/proj/promptflow/docs/how-to-guides/develop-a-tool" -doc_split_yml = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_pipeline/document_split.yml" +documents_folder = "D:\proj\github\ms\promptflow\docs" document_chunk_size = 1024 # test data gen flow configs -flow_path = "/Users/luyao/proj/promptflow/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml" +flow_path = "D:\proj\github\ms\promptflow\examples\test_data_gen\construct_test_data_flow\flow.dag.yaml" # Parallel run step configs prs_instance_count = 2 prs_mini_batch_size = "100kb" prs_max_concurrency_per_instance = 10 -# clean data -clean_data_yml = "/Users/luyao/proj/promptflow/examples/test_data_gen/test_data_gen_pipeline/clean_data.yml" diff --git a/examples/test_data_gen/test_data_gen_pipeline/requirements.txt b/examples/test_data_gen/test_data_gen_pipeline/requirements.txt new file mode 100644 index 00000000000..251940c0794 --- /dev/null +++ b/examples/test_data_gen/test_data_gen_pipeline/requirements.txt @@ -0,0 +1,2 @@ +configargparse +mldesigner diff --git a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py index 65409af4c18..04d995bc194 100644 --- a/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py +++ b/examples/test_data_gen/test_data_gen_pipeline/run_test_data_gen_pipeline.py @@ -1,8 +1,12 @@ +import os + import configargparse from azure.ai.ml import Input, MLClient, dsl, load_component from azure.identity import DefaultAzureCredential from components import clean_test_data_set, document_split +CONFIG_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "config.ini")) + def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str): credential = DefaultAzureCredential(exclude_shared_token_cache_credential=True) @@ -17,10 +21,9 @@ def get_ml_client(subscription_id: str, resource_group: str, workspace_name: str @dsl.pipeline( - # default_compute_target="cpucluster", non_pipeline_inputs=["flow_yml_path", "instance_count", "mini_batch_size", "max_concurrency_per_instance"] ) -def pipeline_func_with_flow( +def test_data_gen_pipeline_with_flow( data, flow_yml_path: str, connection_name: str, # ?? should we override here? @@ -34,9 +37,12 @@ def pipeline_func_with_flow( flow_node = flow_component( data=document_node.outputs.document_node_output, - document_node="${data.document_node}", + text_chunk="${data.text_chunk}", connections={ - "generate_test_data": {"connection": "azure_open_ai_connection"}, + "generate_seed_question": {"connection": connection_name}, + "generate_test_question": {"connection": connection_name}, + "generate_context": {"connection": connection_name}, + "generate_answer": {"connection": connection_name}, }, ) @@ -48,23 +54,44 @@ def pipeline_func_with_flow( if __name__ == "__main__": - # TODO: Add error handling - parser = configargparse.ArgParser(default_config_files=["./config.ini"]) - parser.add_argument("--subscription_id", type=str, help="AzureML workspace subscription id") - parser.add_argument("--resource_group", type=str, help="AzureML workspace resource group name") - parser.add_argument("--workspace_name", type=str, help="AzureML workspace name") - parser.add_argument("--aml_cluster", type=str, help="AzureML cluster name") - parser.add_argument("--documents_folder", type=str, help="Documents folder path") - parser.add_argument("--doc_split_yml", type=str, help="Document split component yml path") - parser.add_argument("--document_chunk_size", type=int, help="Document chunk size") - parser.add_argument("--flow_path", type=str, help="Test data generation flow path") - parser.add_argument("--prs_instance_count", type=int, help="Parallel run step instance count") - parser.add_argument("--prs_mini_batch_size", type=str, help="Parallel run step mini batch size") + if os.path.isfile(CONFIG_FILE): + parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + else: + raise Exception( + f"'{CONFIG_FILE}' does not exist. " + + "Please check if you are under the wrong directory or the file is missing." + ) + parser = configargparse.ArgParser(default_config_files=[CONFIG_FILE]) + parser.add_argument("--subscription_id", required=True, type=str, help="AzureML workspace subscription id") + parser.add_argument("--resource_group", required=True, type=str, help="AzureML workspace resource group name") + parser.add_argument("--workspace_name", required=True, type=str, help="AzureML workspace name") + parser.add_argument("--aml_cluster", required=True, type=str, help="AzureML cluster name") + parser.add_argument( + "--should_skip_doc_split", + required=True, + type=bool, + help="If true, the document split step will be skipped," + + "you will need to provide the document_nodes jsonl file in the config file.", + ) + parser.add_argument( + "--document_nodes_file_path", required=False, type=str, help="Splitted document nodes file path" + ) + parser.add_argument("--documents_folder", required=False, type=str, help="Documents folder path") + parser.add_argument("--document_chunk_size", required=False, type=int, help="Document chunk size") + parser.add_argument("--flow_path", required=True, type=str, help="Test data generation flow path") + parser.add_argument("--prs_instance_count", required=False, type=int, help="Parallel run step instance count") + parser.add_argument("--prs_mini_batch_size", required=False, type=str, help="Parallel run step mini batch size") parser.add_argument( - "--prs_max_concurrency_per_instance", type=int, help="Parallel run step max concurrency per instance" + "--prs_max_concurrency_per_instance", + required=False, + type=int, + help="Parallel run step max concurrency per instance", ) - parser.add_argument("--clean_data_yml", type=str, help="Clean data component yml path") args = parser.parse_args() + if args.should_skip_doc_split and args.document_nodes_file_path is None: + parser.error("--document_nodes_file_path is required when --should_skip_doc_split is True") + elif not args.should_skip_doc_split and args.documents_folder is None: + parser.error("--documents_folder is required when --should_skip_doc_split is False") ml_client = get_ml_client(args.subscription_id, args.resource_group, args.workspace_name) @@ -76,12 +103,12 @@ def pipeline_func_with_flow( "max_concurrency_per_instance": args.prs_max_concurrency_per_instance, } - pipeline_with_flow = pipeline_func_with_flow( + pipeline_with_flow = test_data_gen_pipeline_with_flow( data=data_input, flow_yml_path=args.flow_path, connection_name="azure_open_ai_connection", chunk_size=args.document_chunk_size, - **prs_configs # TODO: Need to do error handling for parsing configs + **prs_configs, ) pipeline_with_flow.compute = args.aml_cluster From 9e5068cd74d823e7f521195a26e75c0f11395410 Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Thu, 18 Jan 2024 10:23:15 +0800 Subject: [PATCH 010/112] rename --- .../construct_test_data_flow/flow.dag.yaml | 59 +- .../generate_answer.py | 4 +- .../construct_test_data_flow/requirements.txt | 0 ...xt.py => validate_and_generate_context.py} | 15 +- ...=> validate_and_generate_seed_question.py} | 17 +- ...=> validate_and_generate_test_question.py} | 13 +- ....jinja2 => validate_context_prompt.jinja2} | 0 ...jinja2 => validate_question_prompt.jinja2} | 0 examples/test_data_gen/text-chunk-data.jsonl | 531 ++++++++++++++++++ 9 files changed, 586 insertions(+), 53 deletions(-) create mode 100644 examples/test_data_gen/construct_test_data_flow/requirements.txt rename examples/test_data_gen/construct_test_data_flow/{generate_context.py => validate_and_generate_context.py} (68%) rename examples/test_data_gen/construct_test_data_flow/{generate_seed_question.py => validate_and_generate_seed_question.py} (57%) rename examples/test_data_gen/construct_test_data_flow/{generate_test_question.py => validate_and_generate_test_question.py} (71%) rename examples/test_data_gen/construct_test_data_flow/{score_context_prompt.jinja2 => validate_context_prompt.jinja2} (100%) rename examples/test_data_gen/construct_test_data_flow/{score_question_prompt.jinja2 => validate_question_prompt.jinja2} (100%) create mode 100644 examples/test_data_gen/text-chunk-data.jsonl diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index 90e6e324ddd..76635613e20 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -1,5 +1,4 @@ -id: template_standard_flow -name: Template Standard Flow +$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json environment: python_requirements_txt: requirements.txt inputs: @@ -16,16 +15,16 @@ inputs: outputs: question: type: string - reference: ${generate_test_question.output.question} + reference: ${validate_and_generate_test_question.output.question} answer: type: string reference: ${generate_answer.output} context: type: string - reference: ${generate_context.output} + reference: ${validate_and_generate_context.output} question_type: type: string - reference: ${generate_test_question.output.question_type} + reference: ${validate_and_generate_test_question.output.question_type} nodes: - name: reasoning_prompt type: prompt @@ -34,7 +33,7 @@ nodes: path: reasoning_prompt.jinja2 inputs: context: ${inputs.text_chunk} - question: ${generate_seed_question.output} + question: ${validate_and_generate_seed_question.output} use_variants: false - name: conditional_prompt type: prompt @@ -43,23 +42,23 @@ nodes: path: conditional_prompt.jinja2 inputs: context: ${inputs.text_chunk} - question: ${generate_seed_question.output} + question: ${validate_and_generate_seed_question.output} use_variants: false -- name: score_context_prompt +- name: validate_context_prompt type: prompt source: type: code - path: score_context_prompt.jinja2 + path: validate_context_prompt.jinja2 inputs: context: ${inputs.text_chunk} use_variants: false -- name: score_seed_question_prompt +- name: validate_seed_question_prompt type: prompt source: type: code - path: score_question_prompt.jinja2 + path: validate_question_prompt.jinja2 inputs: - question: ${generate_seed_question.output} + question: ${validate_and_generate_seed_question.output} use_variants: false - name: seed_question_prompt type: prompt @@ -76,7 +75,7 @@ nodes: path: generate_context_prompt.jinja2 inputs: context: ${inputs.text_chunk} - question: ${generate_test_question.output.question} + question: ${validate_and_generate_test_question.output.question} use_variants: false - name: generate_answer_prompt type: prompt @@ -84,52 +83,52 @@ nodes: type: code path: generate_answer_prompt.jinja2 inputs: - context: ${generate_context.output} - question: ${generate_test_question.output} + context: ${validate_and_generate_context.output} + question: ${validate_and_generate_test_question.output} use_variants: false -- name: generate_seed_question +- name: validate_and_generate_seed_question type: python source: type: code - path: generate_seed_question.py + path: validate_and_generate_seed_question.py inputs: connection: azure_openai_connection model: gpt-35-turbo - score_context_prompt: ${score_context_prompt.output} + validate_context_prompt: ${validate_context_prompt.output} seed_question_prompt: ${seed_question_prompt.output} use_variants: false -- name: generate_test_question +- name: validate_and_generate_test_question type: python source: type: code - path: generate_test_question.py + path: validate_and_generate_test_question.py inputs: connection: azure_openai_connection conditional_prompt: ${conditional_prompt.output} model: gpt-35-turbo reasoning_prompt: ${reasoning_prompt.output} - score_seed_question_prompt: ${score_seed_question_prompt.output} - seed_question: ${generate_seed_question.output} + validate_seed_question_prompt: ${validate_seed_question_prompt.output} + seed_question: ${validate_and_generate_seed_question.output} use_variants: false -- name: score_question_prompt +- name: validate_question_prompt type: prompt source: type: code - path: score_question_prompt.jinja2 + path: validate_question_prompt.jinja2 inputs: - question: ${generate_test_question.output.question} + question: ${validate_and_generate_test_question.output.question} use_variants: false -- name: generate_context +- name: validate_and_generate_context type: python source: type: code - path: generate_context.py + path: validate_and_generate_context.py inputs: connection: azure_openai_connection generate_context_prompt: ${generate_context_prompt.output} model: gpt-35-turbo - question_info: ${generate_test_question.output} - score_question_prompt: ${score_question_prompt.output} + question_info: ${validate_and_generate_test_question.output} + validate_question_prompt: ${validate_question_prompt.output} use_variants: false - name: generate_answer type: python @@ -138,7 +137,7 @@ nodes: path: generate_answer.py inputs: connection: azure_openai_connection - context: ${generate_context.output} + context: ${validate_and_generate_context.output} generate_answer_prompt: ${generate_answer_prompt.output} model: gpt-35-turbo use_variants: false diff --git a/examples/test_data_gen/construct_test_data_flow/generate_answer.py b/examples/test_data_gen/construct_test_data_flow/generate_answer.py index f853ff39639..53d081deb72 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_answer.py +++ b/examples/test_data_gen/construct_test_data_flow/generate_answer.py @@ -19,7 +19,7 @@ def generate_answer( Returns: str: The generated answer. """ - if context is None: - return None + if context == "": + return "" return llm_call(connection, model, generate_answer_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/requirements.txt b/examples/test_data_gen/construct_test_data_flow/requirements.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/test_data_gen/construct_test_data_flow/generate_context.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py similarity index 68% rename from examples/test_data_gen/construct_test_data_flow/generate_context.py rename to examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py index 398d0ca1ab5..d36b92c2ae6 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_context.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_context.py @@ -7,23 +7,24 @@ @tool -def generate_context( +def validate_and_generate_context( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, question_info: dict, generate_context_prompt: str, - score_question_prompt: str + validate_question_prompt: str ): - """ - Generates a context based on the given prompts and question information. + """ + 1. Validates the given question. + 2. Generates a context based on the given prompts and question information. Returns: str: The generated context. """ question = question_info["question"] question_type = question_info["question_type"] - if question is None or ( - question_type != "simple" and not is_valid_question(connection, model, score_question_prompt)): - return None + if question == "" or ( + question_type != "simple" and not is_valid_question(connection, model, validate_question_prompt)): + return "" return llm_call(connection, model, generate_context_prompt) diff --git a/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py similarity index 57% rename from examples/test_data_gen/construct_test_data_flow/generate_seed_question.py rename to examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py index 5977f14f5bf..fd003fa27f0 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_seed_question.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_seed_question.py @@ -7,22 +7,23 @@ @tool -def generate_seed_question( +def validate_and_generate_seed_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, - score_context_prompt: str, + validate_context_prompt: str, seed_question_prompt: str ): - """ - Generates a seed question based on the given prompts. + """ + 1. Validates the given text chunk. + 2. Generates a seed question based on the given prompts. Returns: str: The generated seed question. """ - context_filter = llm_call(connection, model, score_context_prompt) - if not context_filter: - print("invalid context.") - return None + is_valid = llm_call(connection, model, validate_context_prompt) + if not is_valid: + print("invalid text chunk.") + return "" seed_question = llm_call(connection, model, seed_question_prompt) return seed_question diff --git a/examples/test_data_gen/construct_test_data_flow/generate_test_question.py b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py similarity index 71% rename from examples/test_data_gen/construct_test_data_flow/generate_test_question.py rename to examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py index 973ee68e3a4..4f40f3fd029 100644 --- a/examples/test_data_gen/construct_test_data_flow/generate_test_question.py +++ b/examples/test_data_gen/construct_test_data_flow/validate_and_generate_test_question.py @@ -7,25 +7,26 @@ @tool -def generate_test_question( +def validate_and_generate_test_question( connection: Union[OpenAIConnection, AzureOpenAIConnection], model: str, seed_question: str, reasoning_prompt: str, conditional_prompt: str, - score_seed_question_prompt: str, + validate_seed_question_prompt: str, simple_ratio: float = 0.5, reasoning_ratio: float = 0.25, conditional_ratio: float = 0.25 ): - """ - Generates a test question based on the given prompts and distribution ratios. + """ + 1. Validates the given seed question. + 2. Generates a test question based on the given prompts and distribution ratios. Returns: dict: The generated test question and its type. """ - if seed_question is None or not is_valid_question(connection, model, score_seed_question_prompt): - return None + if seed_question == "" or not is_valid_question(connection, model, validate_seed_question_prompt): + return {"question": "", "question_type": ""} testset_distribution = validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio) diff --git a/examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/score_context_prompt.jinja2 rename to examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 diff --git a/examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 similarity index 100% rename from examples/test_data_gen/construct_test_data_flow/score_question_prompt.jinja2 rename to examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 diff --git a/examples/test_data_gen/text-chunk-data.jsonl b/examples/test_data_gen/text-chunk-data.jsonl new file mode 100644 index 00000000000..7dce5a6259a --- /dev/null +++ b/examples/test_data_gen/text-chunk-data.jsonl @@ -0,0 +1,531 @@ +{"text_chunk": "Connections\n\nConnections are for storing information about how to access external services like LLMs: endpoint, api keys etc.\n\n- In your local development environment, the connections are persisted in your local machine with keys encrypted.\n- In Azure AI, connections can be configured to be shared across the entire workspace. Secrets associated with connections are securely persisted in the corresponding Azure Key Vault, adhering to robust security and compliance standards.\n\nPrompt flow provides a variety of pre-built connections, including Azure Open AI, Open AI, etc. These pre-built connections enable seamless integration with these resources within the built-in tools. Additionally, you have the flexibility to create custom connection types using key-value pairs, empowering them to tailor the connections to their specific requirements, particularly in Python tools.\n\n| Connection type | Built-in tools |\n| ------------------------------------------------------------ | ------------------------------- |\n| Azure Open AI | LLM or Python |\n| Open AI | LLM or Python |\n| Cognitive Search | Vector DB Lookup or Python |\n| Serp | Serp API or Python |\n| Custom | Python |\n\nBy leveraging connections in prompt flow, you can easily establish and manage connections to external APIs and data sources, facilitating efficient data exchange and interaction within their AI applications."} +{"text_chunk": "Next steps\n\n- Create connections"} +{"text_chunk": "Flows\n\nA flow in prompt flow is a DAG of functions (we call them tools). These functions/tools connected via input/output dependencies and executed based on the topology by prompt flow executor.\n\nA flow is represented as a YAML file and can be visualized with our Prompt flow for VS Code extension. Here is an example:\n\n!flow_dag"} +{"text_chunk": "Flow types\n\nPrompt flow has three flow types:\n\n- **Standard flow** and **Chat flow**: these two are for you to develop your LLM application. The primary difference between the two lies in the additional support provided by the \"Chat Flow\" for chat applications. For instance, you can define chat_history, chat_input, and chat_output for your flow. The prompt flow, in turn, will offer a chat-like experience (including conversation history) during the development of the flow. Moreover, it also provides a sample chat application for deployment purposes.\n- **Evaluation flow** is for you to test/evaluate the quality of your LLM application (standard/chat flow). It usually run on the outputs of standard/chat flow, and compute some metrics that can be used to determine whether the standard/chat flow performs well. E.g. is the answer accurate? is the answer fact-based?"} +{"text_chunk": "When to use standard flow vs. chat flow?\n\nAs a general guideline, if you are building a chatbot that needs to maintain conversation history, try chat flow. In most other cases, standard flow should serve your needs.\n\nOur examples should also give you an idea when to use what:\n- examples/flows/standard\n- examples/flows/chat"} +{"text_chunk": "Next steps\n\n- Quick start\n- Initialize and test a flow\n- Run and evaluate a flow\n- Tune prompts using variants"} +{"text_chunk": "Tools\n\nPrompt flow provides 3 basic tools:\n- LLM: The LLM tool allows you to write custom prompts and leverage large language models to achieve specific goals, such as summarizing articles, generating customer support responses, and more.\n- Python: The Python tool enables you to write custom Python functions to perform various tasks, such as fetching web pages, processing intermediate data, calling third-party APIs, and more.\n- Prompt: The Prompt tool allows you to prepare a prompt as a string for more complex use cases or for use in conjunction with other prompt tools or python tools."} +{"text_chunk": "More tools\n\nOur partners also contributes other useful tools for advanced scenarios, here are some links:\n- Vector DB Lookup: vector search tool that allows users to search top k similar vectors from vector database.\n- Faiss Index Lookup: querying within a user-provided Faiss-based vector store."} +{"text_chunk": "Custom tools\n\nYou can create your own tools that can be shared with your team or anyone in the world. \nLearn more on Create and Use Tool Package"} +{"text_chunk": "Next steps\n\nFor more information on the available tools and their usage, visit the our reference doc."} +{"text_chunk": "Variants\n\nA variant refers to a specific version of a tool node that has distinct settings. Currently, variants are supported only in the LLM tool. For example, in the LLM tool, a new variant can represent either a different prompt content or different connection settings.\n\nSuppose you want to generate a summary of a news article. You can set different variants of prompts and settings like this:\n\n| Variants | Prompt | Connection settings |\n| --------- | ------------------------------------------------------------ | ------------------- |\n| Variant 0 | `Summary: {{input sentences}}` | Temperature = 1 |\n| Variant 1 | `Summary: {{input sentences}}` | Temperature = 0.7 |\n| Variant 2 | `What is the main point of this article? {{input sentences}}` | Temperature = 1 |\n| Variant 3 | `What is the main point of this article? {{input sentences}}` | Temperature = 0.7 |\n\nBy utilizing different variants of prompts and settings, you can explore how the model responds to various inputs and outputs, enabling you to discover the most suitable combination for your requirements."} +{"text_chunk": "Benefits of using variants\n\n- **Enhance the quality of your LLM generation**: By creating multiple variants of the same LLM node with diverse prompts and configurations, you can identify the optimal combination that produces high-quality content aligned with your needs.\n- **Save time and effort**: Even slight modifications to a prompt can yield significantly different results. It's crucial to track and compare the performance of each prompt version. With variants, you can easily manage the historical versions of your LLM nodes, facilitating updates based on any variant without the risk of forgetting previous iterations. This saves you time and effort in managing prompt tuning history.\n- **Boost productivity**: Variants streamline the optimization process for LLM nodes, making it simpler to create and manage multiple variations. You can achieve improved results in less time, thereby increasing your overall productivity.\n- **Facilitate easy comparison**: You can effortlessly compare the results obtained from different variants side by side, enabling you to make data-driven decisions regarding the variant that generates the best outcomes."} +{"text_chunk": "Next steps\n\n- Tune prompts with variants"} +{"text_chunk": "Design principles\n\nWhen we started this project, LangChain already became popular esp. after the ChatGPT launch. One of the questions we\u2019ve been asked is what\u2019s the difference between prompt flow and LangChain. This article is to elucidate the reasons for building prompt flow and the deliberate design choices we have made. To put it succinctly, prompt flow is a suite of development tools for you to build LLM apps with a strong emphasis of quality through experimentations, not a framework - which LangChain is.\n\nWhile LLM apps are mostly in exploration stage, Microsoft started in this area a bit earlier and we\u2019ve had the opportunity to observe how developers are integrating LLMs into existing systems or build new applications. These invaluable insights have shaped the fundamental design principles of prompt flow."} +{"text_chunk": "1. Expose the prompts vs. hiding them\n\nThe core essence of LLM applications lies in the prompts themselves, at least for today. When developing a reasonably complex LLM application, the majority of development work should be \u201ctuning\u201d the prompts (note the intentional use of the term \"tuning,\" which we will delve into further later on). Any framework or tool trying to help in this space should focus on making prompt tuning easier and more straightforward. On the other hand, prompts are very volatile, it's unlikely to write a single prompt that can work across different models or even different version of same models. Building a successful LLM-based application, you have to understand every prompt introduced, so that you can tune it when necessary. LLM is simply not powerful or deterministic enough that you can use a prompt written by others like you use libraries in traditional programming languages.\n\nIn this context, any design that tries to provide a smart function or agent by encapsulating a few prompts in a library is unlikely to yield favorable results in real-world scenarios. And hiding prompts inside a library\u2019s code base only makes it\u2019s hard for people to improve or tailor the prompts to suit their specific needs.\n\nPrompt flow, being positioned as a tool, refrains from wrapping any prompts within its core codebase. The only place you will see prompts are our sample flows, which are, of course, available for adoption and utilization. Every prompt should be authored and controlled by the developers themselves, rather than relying on us."} +{"text_chunk": "2. A new way of work\n\nLLMs possess remarkable capabilities that enable developers to enhance their applications without delving deep into the intricacies of machine learning. In the meantime, LLMs make these apps more stochastic, which pose new challenges to application development. Merely asserting \"no exception\" or \"result == x\" in gated tests is no longer sufficient. Adopting a new methodology and employing new tools becomes imperative to ensure the quality of LLM applications \u2014 an entirely novel way of working is required.\n\nAt the center of this paradigm shift is evaluation, a term frequently used in machine learning space, refers to the process of assessing the performance and quality of a trained model. It involves measuring how well the model performs on a given task or dataset, which plays a pivotal role in understanding the model's strengths, weaknesses, and overall effectiveness. Evaluation metrics and techniques vary depending on the specific task and problem domain. Some common metrics include accuracy, precision and recall, you probably already familiar with. Now the LLM apps share similarities with machine learning models, they requires an evaluation-centric approach integrated into the development workflow, with a robust set of metrics and evaluation forming the foundation for ensuring the quality of LLM applications.\n\nPrompt flow offers a range of tools to streamline the new way of work:\n\n* Develop your evaluation program as Evaluation flow to calculate metrics for your app/flow, learn from our sample evaluation flows.\n* Iterate on your application flow and run evaluation flows via the SDK/CLI, allowing you to compare metrics and choose the optimal candidate for release. These iterations include trying different prompts, different LLM parameters like temperature etc. - this is referred as \u201ctuning\u201d process earlier, or sometime referred as experimentation.\n* Integrate the evaluation into your CI/CD pipeline, aligning the assertions in your gated tests with the selected metrics.\n\n\nPrompt flow introduces two conceptual components to facilitate this workflow:\n\n* Evaluation flow: a flow type that indicates this flow is not for deploy or integrate into your app, it\u2019s for evaluating an app/flow performance.\n* Run: every time you run your flow with data, or run an evaluation on the output of a flow, a Run object is created to manage the history and allow for comparison and additional analysis.\n\nWhile new concepts introduce additional cognitive load, we firmly believe they hold greater importance compared to abstracting different LLM APIs or vector database APIs."} +{"text_chunk": "3. Optimize for \u201cvisibility\u201d\n\nThere are quite some interesting application patterns emerging because of LLMs, like Retrieval Augmented Generation (RAG), ReAct and more. Though how LLMs work may remain enigmatic to many developers, how LLM apps work is not - they essentially involve a series of calls to external services such as LLMs, databases, and search engines, all glued together. Architecturally there isn\u2019t much new, patterns like RAG and ReAct are both straightforward to implement once a developer understands what they are - plain Python programs with API calls to external services can totally serve the purpose effectively.\n\nBy observing many internal use cases, we learned that deeper insight into the detail of the execution is critical. Establishing a systematic method for tracking interactions with external systems is one of design priority. Consequently, We adopted an unconventional approach - prompt flow has a YAML file describing how function calls (we call them Tools) are executed and connected into a Directed Acyclic Graph (DAG). \n\nThis approach offers several key benefits, primarily centered around **enhanced visibility**:\n1) During development, your flow can be visualized in an intelligible manner, enabling clear identification of any faulty components. As a byproduct, you obtain an architecturally descriptive diagram that can be shared with others.\n2) Each node in the flow has it\u2019s internal detail visualized in a consistent way.\n3) Single nodes can be individually run or debugged without the need to rerun previous nodes.\n\n\n!promptflow-dag\n\nThe emphasis on visibility in prompt flow's design helps developers to gain a comprehensive understanding of the intricate details of their applications. This, in turn, empowers developers to engage in effective troubleshooting and optimization.\n\nDespite there're some control flow features like \"activate-when\" to serve the needs of branches/switch-case, we do not intend to make Flow itself Turing-complete. If you want to develop an agent which is fully dynamic and guided by LLM, leveraging Semantic Kernel together with prompt flow would be a favorable option."} +{"text_chunk": "Dev Setup"} +{"text_chunk": "Set up process\n\n- First create a new conda environment. Please specify python version as 3.9.\n `conda create -n python=3.9`.\n- Activate the env you created.\n- Set environment variable `PYTHONPATH` in your new conda environment.\n `conda env config vars set PYTHONPATH=\\promptflow`.\n Once you have set the environment variable, you have to reactivate your environment.\n `conda activate `.\n- In root folder, run `python scripts/building/dev_setup.py --promptflow-extra-deps azure` to install the package and dependencies."} +{"text_chunk": "How to run tests"} +{"text_chunk": "Set up your secrets\n\n`dev-connections.json.example` is a template about connections provided in `src/promptflow`. You can follow these steps to refer to this template to configure your connection for the test cases:\n1. `cd ./src/promptflow`\n2. Run the command `cp dev-connections.json.example connections.json`;\n3. Replace the values in the json file with your connection info;\n4. Set the environment `PROMPTFLOW_CONNECTIONS='connections.json'`;\n\nAfter above setup process is finished. You can use `pytest` command to run test, for example in root folder you can:"} +{"text_chunk": "Run tests via command\n\n- Run all tests under a folder: `pytest src/promptflow/tests -v`\n- Run a single test: ` pytest src/promptflow/tests/promptflow_test/e2etests/test_executor.py::TestExecutor::test_executor_basic_flow -v`"} +{"text_chunk": "Run tests in VSCode\n\n1. Set up your python interperter\n\n- Open the Command Palette (Ctrl+Shift+P) and select `Python: Select Interpreter`.\n\n!img0\n\n- Select existing conda env which you created previously.\n\n!img1\n\n2. Set up your test framework and directory\n\n- Open the Command Palette (Ctrl+Shift+P) and select `Python: Configure Tests`.\n\n!img2\n\n- Select `pytest` as test framework.\n\n!img3\n\n- Select `Root directory` as test directory.\n\n!img4\n\n3. Exclude specific test folders.\n\nYou can exclude specific test folders if you don't have some extra dependency to avoid VS Code's test discovery fail.\nFor example, if you don't have azure dependency, you can exclude `sdk_cli_azure_test`.\nOpen `.vscode/settings.json`, write `\"--ignore=src/promptflow/tests/sdk_cli_azure_test\"` to `\"python.testing.pytestArgs\"`.\n\n!img6\n\n4. Click the `Run Test` button on the left\n\n!img5"} +{"text_chunk": "Run tests in pycharm\n\n1. Set up your pycharm python interpreter\n\n!img0\n\n2. Select existing conda env which you created previously\n\n!img1\n\n3. Run test, right-click the test name to run, or click the green arrow button on the left.\n\n!img2"} +{"text_chunk": "Record and replay tests\n\nPlease refer to Replay End-to-End Tests to learn how to record and replay tests."} +{"text_chunk": "How to write docstring.\n\nA clear and consistent API documentation is crucial for the usability and maintainability of our codebase. Please refer to API Documentation Guidelines to learn how to write docstring when developing the project."} +{"text_chunk": "How to write tests\n\n- Put all test data/configs under `src/promptflow/tests/test_configs`.\n- Write unit tests:\n - Flow run: `src/promptflow/tests/sdk_cli_test/unittest/`\n - Flow run in azure: `src/promptflow/tests/sdk_cli_azure_test/unittest/`\n- Write e2e tests:\n - Flow run: `src/promptflow/tests/sdk_cli_test/e2etests/`\n - Flow run in azure: `src/promptflow/tests/sdk_cli_azure_test/e2etests/`\n- Test file name and the test case name all start with `test_`.\n- A basic test example, see test_connection.py."} +{"text_chunk": "Test structure\n\nCurrently all tests are under `src/promptflow/tests/` folder:\n\n- tests/\n - promptflow/\n - sdk_cli_test/\n - e2etests/\n - unittests/\n - sdk_cli_azure_test/\n - e2etests/\n - unittests/\n - test_configs/\n - connections/\n - datas/\n - flows/\n - runs/\n - wrong_flows/\n - wrong_tools/\n\nWhen you want to add tests for a new feature, you can add new test file let's say a e2e test file `test_construction.py`\nunder `tests/promptflow/**/e2etests/`.\n\nOnce the project gets more complicated or anytime you find it necessary to add new test folder and test configs for\na specific feature, feel free to split the `promptflow` to more folders, for example:\n\n- tests/\n - (Test folder name)/\n - e2etests/\n - test_xxx.py\n - unittests/\n - test_xxx.py\n - test_configs/\n - (Data or config folder name)/"} +{"text_chunk": "Promptflow Reference Documentation Guide"} +{"text_chunk": "Overview\n\nThis guide describes how to author Python docstrings for promptflow public interfaces. See our doc site at Promptflow API reference documentation."} +{"text_chunk": "Principles\n\n- **Coverage**: Every public object must have a docstring. For private objects, docstrings are encouraged but not required.\n- **Style**: All docstrings should be written in Sphinx style noting all types and if any exceptions are raised.\n- **Relevance**: The documentation is up-to-date and relevant to the current version of the product.\n- **Clarity**: The documentation is written in clear, concise language that is easy to understand.\n- **Consistency**: The documentation has a consistent format and structure, making it easy to navigate and follow."} +{"text_chunk": "How to write the docstring\n\nFirst please read through Sphinx style to have a basic understanding of sphinx style docstring."} +{"text_chunk": "Write class docstring\n\nLet's start with a class example:\n```python\nfrom typing import Dict, Optional, Union\nfrom promptflow import PFClient\n\nclass MyClass:\n \"\"\"One-line summary of the class.\n\n More detailed explanation of the class. May include below notes, admonitions, code blocks.\n\n .. note::\n\n Here are some notes to show, with a nested python code block:\n\n .. code-block:: python\n\n from promptflow import MyClass, PFClient\n obj = MyClass(PFClient())\n\n .. admonition:: [Title of the admonition]\n\n Here are some admonitions to show.\n\n :param client: Descrition of the client.\n :type client: ~promptflow.PFClient\n :param param_int: Description of the parameter.\n :type param_int: Optional[int]\n :param param_str: Description of the parameter.\n :type param_str: Optional[str]\n :param param_dict: Description of the parameter.\n :type param_dict: Optional[Dict[str, str]]\n \"\"\"\n def __init__(\n client: PFClient,\n param_int: Optional[int] = None,\n param_str: Optional[str] = None,\n param_dict: Optional[Dict[str, str]] = None,\n ) -> None:\n \"\"\"No docstring for __init__, it should be written in class definition above.\"\"\"\n ...\n\n\n```\n\n**Notes**:\n\n1. One-line summary is required. It should be clear and concise.\n2. Detailed explanation is encouraged but not required. This part may or may not include notes, admonitions and code blocks.\n - The format like `.. note::` is called `directive`. Directives are a mechanism to extend the content of reStructuredText. Every directive declares a block of content with specific role. Start a new line with `.. directive_name::` to use the directive. \n - The directives used in the sample(`note/admonition/code-block`) should be enough for basic usage of docstring in our project. But you are welcomed to explore more Directives.\n3. Parameter description and type is required.\n - A pair of `:param [ParamName]:` and `:type [ParamName]:` is required.\n - If the type is a promptflow public class, use the `full path to the class` and prepend it with a \"~\". This will create a link when the documentation is rendered on the doc site that will take the user to the class reference documentation for more information.\n ```text\n :param client: Descrition of the client.\n :type client: ~promptflow.PFClient\n ```\n - Use `Union/Optional` when appropriate in function declaration. And use the same annotaion after `:type [ParamName]:`\n ```text\n :type param_int: Optional[int]\n ```\n4. For classes, include docstring in definition only. If you include a docstring in both the class definition and the constructor (init method) docstrings, it will show up twice in the reference docs.\n5. Constructors (def `__init__`) should return `None`, per PEP 484 standards.\n6. To create a link for promptflow class on our doc site. `~promptflow.xxx.MyClass` alone only works after `:type [ParamName]` and `:rtype:`. If you want to achieve the same effect in docstring summary, you should use it with `:class:`:\n ```python\n \"\"\"\n An example to achieve link effect in summary for :class:`~promptflow.xxx.MyClass`\n For function, use :meth:`~promptflow.xxx.my_func`\n \"\"\"\n ```\n\n7. There are some tricks to highlight the content in your docstring:\n - Single backticks (`): Single backticks are used to represent inline code elements within the text. It is typically used to highlight function names, variable names, or any other code elements within the documentation.\n - Double backticks(``): Double backticks are typically used to highlight a literal value.\n\n8. If there are any class level constants you don't want to expose to doc site, make sure to add `_` in front of the constant to hide it."} +{"text_chunk": "Write function docstring\n\n```python\nfrom typing import Optional\n\ndef my_method(param_int: Optional[int] = None) -> int:\n \"\"\"One-line summary\n\n Detailed explanations.\n\n :param param_int: Description of the parameter.\n :type param_int: int\n :raises [ErrorType1]: [ErrorDescription1]\n :raises [ErrorType2]: [ErrorDescription2]\n :return: Description of the return value.\n :rtype: int\n \"\"\"\n ...\n```\n\nIn addition to `class docstring` notes:\n\n1. Function docstring should include return values.\n - If return type is promptflow class, we should also use `~promptflow.xxx.[ClassName]`.\n2. Function docstring should include exceptions that may be raised in this function.\n - If exception type is `PromptflowException`, use `~promptflow.xxx.[ExceptionName]`\n - If multiple exceptions are raised, just add new lines of `:raises`, see the example above."} +{"text_chunk": "How to build doc site locally\n\nYou can build the documentation site locally to preview the final effect of your docstring on the rendered site. This will provide you with a clear understanding of how your docstring will appear on our site once your changes are merged into the main branch.\n\n1. Setup your dev environment, see dev_setup for details. Sphinx will load all source code to process docstring.\n - Skip this step if you just want to build the doc site without reference doc, but do remove `-WithReferenceDoc` from the command in step 3.\n2. Install `langchain` package since it is used in our code but not covered in `dev_setup`.\n3. Open a `powershell`, activate the conda env and navigate to `/scripts/docs` , run `doc_generation.ps1`:\n ```pwsh\n cd scripts\\docs\n .\\doc_generation.ps1 -WithReferenceDoc -WarningAsError\n ```\n - For the first time you execute this command, it will take some time to install `sphinx` dependencies. After the initial installation, next time you can add param `-SkipInstall` to above command to save some time for dependency check.\n4. Check warnings/errors in the build log, fix them if any, then build again.\n5. Open `scripts/docs/_build/index.html` to preview the local doc site."} +{"text_chunk": "Additional comments\n\n- **Utilities**: The autoDocstring VSCode extension or GitHub Copilot can help autocomplete in this style for you.\n\n- **Advanced principles**\n - Accuracy: The documentation accurately reflects the features and functionality of the product.\n - Completeness: The documentation covers all relevant features and functionality of the product.\n - Demonstration: Every docstring should include an up-to-date code snippet that demonstrates how to use the product effectively."} +{"text_chunk": "References\n\n- AzureML v2 Reference Documentation Guide\n- Azure SDK for Python documentation guidelines\n- How to document a Python API"} +{"text_chunk": "Replay end-to-end tests\n\n* This document introduces replay tests for those located in sdk_cli_azure_test and sdk_cli_test.\n* The primary purpose of replay tests is to avoid the need for credentials, Azure workspaces, OpenAI tokens, and to directly test prompt flow behavior.\n* Although there are different techniques behind recording/replaying, there are some common steps to run the tests in replay mode.\n* The key handle of replay tests is the environment variable `PROMPT_FLOW_TEST_MODE`."} +{"text_chunk": "How to run tests in replay mode\n\nAfter cloning the full repo and setting up the proper test environment following dev_setup.md, run the following command in the root directory of the repo:\n\n1. If you have changed/affected tests in __sdk_cli_test__ : Copy or rename the file dev-connections.json.example to `connections.json` in the same folder.\n2. In your Python environment, set the environment variable `PROMPT_FLOW_TEST_MODE` to `'replay'` and run the test(s).\n\nThese tests should work properly without any real connection settings."} +{"text_chunk": "Test modes\n\nThere are 3 representative values of the environment variable `PROMPT_FLOW_TEST_MODE`\n- `live`: Tests run against the real backend, which is the way traditional end-to-end tests do.\n- `record`: Tests run against the real backend, and network traffic will be sanitized (filter sensitive and unnecessary requests/responses) and recorded to local files (recordings).\n- `replay`: There is no real network traffic between SDK/CLI and the backend, tests run against local recordings."} +{"text_chunk": "Update test recordings\n\nTo record a test, don\u2019t forget to clone the full repo and set up the proper test environment following dev_setup.md:\n1. Prepare some data.\n * If you have changed/affected tests in __sdk_cli_test__: Copy or rename the file dev-connections.json.example to `connections.json` in the same folder.\n * If you have changed/affected tests in __sdk_cli_azure_test__: prepare your Azure ML workspace, make sure your Azure CLI logged in, and set the environment variable `PROMPT_FLOW_SUBSCRIPTION_ID`, `PROMPT_FLOW_RESOURCE_GROUP_NAME`, `PROMPT_FLOW_WORKSPACE_NAME` and `PROMPT_FLOW_RUNTIME_NAME` (if needed) pointing to your workspace.\n2. Record the test.\n * Specify the environment variable `PROMPT_FLOW_TEST_MODE` to `'record'`. If you have a `.env` file, we recommend specifying it there. Here is an example .env file. Then, just run the test that you want to record.\n3. Once the test completed.\n * If you have changed/affected tests in __sdk_cli_azure_test__: There should be one new YAML file located in `src/promptflow/tests/test_configs/recordings/`, containing the network traffic of the test.\n * If you have changed/affected tests in __sdk_cli_test__: There may be changes in the folder `src/promptflow/tests/test_configs/node_recordings/`. Don\u2019t worry if there are no changes, because similar LLM calls may have been recorded before."} +{"text_chunk": "Techniques behind replay test"} +{"text_chunk": "Sdk_cli_azure_test\n\nEnd-to-end tests for pfazure aim to test the behavior of the PromptFlow SDK/CLI as it interacts with the service. This process can be time-consuming, error-prone, and require credentials (which are unavailable to pull requests from forked repositories); all of these go against our intention for a smooth development experience.\n\nTherefore, we introduce replay tests, which leverage VCR.py to record all required network traffic to local files and replay during tests. In this way, we avoid the need for credentials, speed up, and stabilize the test process."} +{"text_chunk": "Sdk_cli_test\n\nsdk_cli_test often doesn\u2019t use a real backend. It will directly invokes LLM calls from localhost. Thus the key target of replay tests is to avoid the need for OpenAI tokens. If you have OpenAI / Azure OpenAI tokens yourself, you can try recording the tests. Record Storage will not record your own LLM connection, but only the inputs and outputs of the LLM calls.\n\nThere are also limitations. Currently, recorded calls are:\n* AzureOpenAI calls\n* OpenAI calls\n* tool name \"fetch_text_content_from_url\" and tool name \"my_python_tool\""} +{"text_chunk": "Add conditional control to a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nIn prompt flow, we support control logic by activate config, like if-else, switch. Activate config enables conditional execution of nodes within your flow, ensuring that specific actions are taken only when the specified conditions are met.\n\nThis guide will help you learn how to use activate config to add conditional control to your flow."} +{"text_chunk": "Prerequisites\n\nPlease ensure that your promptflow version is greater than `0.1.0b5`."} +{"text_chunk": "Usage\n\nEach node in your flow can have an associated activate config, specifying when it should execute and when it should bypass. If a node has activate config, it will only be executed when the activate condition is met. The configuration consists of two essential components:\n- `activate.when`: The condition that triggers the execution of the node. It can be based on the outputs of a previous node, or the inputs of the flow.\n- `activate.is`: The condition's value, which can be a constant value of string, boolean, integer, double.\n\nYou can manually change the flow.dag.yaml in the flow folder or use the visual editor in VS Code Extension to add activate config to nodes in the flow.\n\n::::{tab-set}\n:::{tab-item} YAML\n:sync: YAML\n\nYou can add activate config in the node section of flow yaml.\n```yaml\nactivate:\n when: ${node.output}\n is: true\n```\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n- Click `Visual editor` in the flow.dag.yaml to enter the flow interface.\n!visual_editor\n\n- Click on the `Activation config` section in the node you want to add and fill in the values for \"when\" and \"is\".\n!activate_config\n\n:::\n\n::::"} +{"text_chunk": "Further details and important notes\n1. If the node using the python tool has an input that references a node that may be bypassed, please provide a default value for this input whenever possible. If there is no default value for input, the output of the bypassed node will be set to None.\n\n !provide_default_value\n\n2. It is not recommended to directly connect nodes that might be bypassed to the flow's outputs. If it is connected, the output will be None and a warning will be raised.\n\n !output_bypassed\n\n3. In a conditional flow, if a node has activate config, we will always use this config to determine whether the node should be bypassed. If a node is bypassed, its status will be marked as \"Bypassed\", as shown in the figure below Show. There are three situations in which a node is bypassed.\n\n !bypassed_nodes\n\n\n (1) If a node has activate config and the value of `activate.when` is not equals to `activate.is`, it will be bypassed. If you want to fore a node to always be executed, you can set the activate config to `when dummy is dummy` which always meets the activate condition.\n\n !activate_condition_always_met\n\n (2) If a node has activate config and the node pointed to by `activate.when` is bypassed, it will be bypassed.\n\n !activate_when_bypassed\n\n (3) If a node does not have activate config but depends on other nodes that have been bypassed, it will be bypassed.\n\n !dependencies_bypassed"} +{"text_chunk": "Example flow\n\nLet's illustrate how to use activate config with practical examples.\n\n- If-Else scenario: Learn how to develop a conditional flow for if-else scenarios. View Example\n- Switch scenario: Explore conditional flow for switch scenarios. View Example"} +{"text_chunk": "Next steps\n\n- Run and evaluate a flow"} +{"text_chunk": "Deploy a flow using development server\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nOnce you have created and thoroughly tested a flow, you can use it as an HTTP endpoint.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nWe are going to use the web-classification as\nan example to show how to deploy a flow.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nNote: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in \nserving mode, white space in connection name will be removed directly from environment variable name. For instance, \nif there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the \nfunction will attempt to retrieve 'chat_deployment_name' from the environment variable \n'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original \nvalue as a fallback.\n\n\nThe following CLI commands allows you serve a flow folder as an endpoint. By running this command, a flask app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.\n```bash"} +{"text_chunk": "Serve the flow at localhost:8080\npf flow serve --source --port 8080 --host localhost\n```\n\nThe expected result is as follows if the flow served successfully, and the process will keep alive until it be killed manually.\n\n!img\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\nIn visual editor, choose:\n!img\nthen choose format:\n!img\nthen in yaml editor:\n!img\n:::\n::::"} +{"text_chunk": "Test endpoint\n::::{tab-set}\n:::{tab-item} Bash\nYou could open another terminal to test the endpoint with the following command:\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```\n:::\n:::{tab-item} PowerShell\nYou could open another terminal to test the endpoint with the following command:\n```powershell\nInvoke-WebRequest -URI http://localhost:8080/score -Body '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -Method POST -ContentType \"application/json\"\n```\n:::\n:::{tab-item} Test Page\nThe development server has a built-in web page you can use to test the flow. Open 'http://localhost:8080' in your browser.\n!img\n:::\n::::"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using docker.\n- See how to deploy a flow using kubernetes."} +{"text_chunk": "Deploy a flow using Docker\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are two steps to deploy a flow using docker:\n1. Build the flow as docker format.\n2. Build and run the docker image."} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker."} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files"} +{"text_chunk": "Deploy with Docker\nWe are going to use the web-classification as\nan example to show how to deploy with docker.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification."} +{"text_chunk": "Build a flow as docker format app\n\nUse the command below to build a flow as docker format app:\n\n```bash\npf flow build --source ../../flows/standard/web-classification --output dist --format docker\n```\n\nNote that all dependent connections must be created before exporting as docker."} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `promptflow-serve`.\n\nRun the command below to build image:\n\n```bash\ndocker build dist -t web-classification-serve\n```"} +{"text_chunk": "Run Docker image\n\nRun the docker image will start a service to serve the flow inside the container."} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work."} +{"text_chunk": "Run with `docker run`\n\nYou can run the docker image directly set via below commands:\n```bash"} +{"text_chunk": "The started service will listen on port 8080.You can map the port to any port on the host machine as you want.\ndocker run -p 8080:8080 -e OPEN_AI_CONNECTION_API_KEY= web-classification-serve\n```"} +{"text_chunk": "Test the endpoint\nAfter start the service, you can use curl to test it:\n\n```bash\ncurl http://localhost:8080/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n```"} +{"text_chunk": "Next steps\n- Try the example here.\n- See how to deploy a flow using kubernetes."} +{"text_chunk": "Deploy a flow using Kubernetes\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThere are four steps to deploy a flow using Kubernetes:\n1. Build the flow as docker format.\n2. Build the docker image.\n3. Create Kubernetes deployment yaml.\n4. Apply the deployment."} +{"text_chunk": "Build a flow as docker format\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nNote that all dependent connections must be created before building as docker.\n```bash"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as docker format:\n```bash\npf flow build --source --output --format docker\n```\n:::\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nClick the button below to build a flow as docker format:\n!img\n:::\n::::\n\nNote that all dependent connections must be created before exporting as docker."} +{"text_chunk": "Docker format folder structure\n\nExported Dockerfile & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files\n - ...\n- connections: the folder contains yaml files to create all related connections\n - ...\n- Dockerfile: the dockerfile to build the image\n- start.sh: the script used in `CMD` of `Dockerfile` to start the service\n- runit: the folder contains all the runit scripts\n - ...\n- settings.json: a json file to store the settings of the docker image\n- README.md: Simple introduction of the files"} +{"text_chunk": "Deploy with Kubernetes\nWe are going to use the web-classification as\nan example to show how to deploy with Kubernetes.\n\nPlease ensure you have create the connection required by flow, if not, you could\nrefer to Setup connection for web-classification.\n\nAdditionally, please ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions."} +{"text_chunk": "Build Docker image\n\nLike other Dockerfile, you need to build the image first. You can tag the image with any name you want. In this example, we use `web-classification-serve`.\n\nThen run the command below:\n\n```bash\ncd \ndocker build . -t web-classification-serve\n```"} +{"text_chunk": "Create Kubernetes deployment yaml.\nThe Kubernetes deployment yaml file acts as a guide for managing your docker container in a Kubernetes pod. It clearly specifies important information like the container image, port configurations, environment variables, and various settings. Below, you'll find a simple deployment template that you can easily customize to meet your needs.\n\n**Note**: You need encode the secret using base64 firstly and input the as 'open-ai-connection-api-key' in the deployment configuration. For example, you can run below commands in linux:\n```bash\nencoded_secret=$(echo -n | base64)\n```\n\n```yaml\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n name: \n---\napiVersion: v1\nkind: Secret\nmetadata:\n name: open-ai-connection-api-key\n namespace: \ntype: Opaque\ndata:\n open-ai-connection-api-key: \n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web-classification-service\n namespace: \nspec:\n type: NodePort\n ports:\n - name: http\n port: 8080\n targetPort: 8080\n nodePort: 30123\n selector:\n app: web-classification-serve-app\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-classification-serve-app\n namespace: \nspec:\n selector:\n matchLabels:\n app: web-classification-serve-app\n template:\n metadata:\n labels:\n app: web-classification-serve-app\n spec:\n containers:\n - name: web-classification-serve-container\n image: \n imagePullPolicy: Never\n ports:\n - containerPort: 8080\n env:\n - name: OPEN_AI_CONNECTION_API_KEY\n valueFrom:\n secretKeyRef:\n name: open-ai-connection-api-key\n key: open-ai-connection-api-key\n```"} +{"text_chunk": "Apply the deployment.\nBefore you can deploy your application, ensure that you have set up a Kubernetes cluster and installed kubectl if it's not already installed. In this documentation, we will use Minikube as an example. To start the cluster, execute the following command:\n```bash\nminikube start\n```\nOnce your Kubernetes cluster is up and running, you can proceed to deploy your application by using the following command:\n```bash\nkubectl apply -f deployment.yaml\n```\nThis command will create the necessary pods to run your application within the cluster.\n\n**Note**: You need replace below with your specific pod_name. You can retrieve it by running `kubectl get pods -n web-classification`."} +{"text_chunk": "Retrieve flow service logs of the container\nThe kubectl logs command is used to retrieve the logs of a container running within a pod, which can be useful for debugging, monitoring, and troubleshooting applications deployed in a Kubernetes cluster.\n\n```bash\nkubectl -n logs \n```"} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in containers.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```\nYou'll need to set up the environment variables in the container to make the connections work."} +{"text_chunk": "Test the endpoint\n- Option1:\n\n Once you've started the service, you can establish a connection between a local port and a port on the pod. This allows you to conveniently test the endpoint from your local terminal.\n To achieve this, execute the following command:\n\n ```bash\n kubectl port-forward : -n \n ```\n With the port forwarding in place, you can use the curl command to initiate the endpoint test:\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```\n\n- Option2:\n\n `minikube service web-classification-service --url -n ` runs as a process, creating a tunnel to the cluster. The command exposes the service directly to any program running on the host operating system.\n\n The command above will retrieve the URL of a service running within a Minikube Kubernetes cluster (e.g. http://:), which you can click to interact with the flow service in your web browser. Alternatively, you can use the following command to test the endpoint: \n\n **Note**: Minikube will use its own external port instead of nodePort to listen to the service. So please substitute with the port obtained above.\n\n ```bash\n curl http://localhost:/score --data '{\"url\":\"https://play.google.com/store/apps/details?id=com.twitter.android\"}' -X POST -H \"Content-Type: application/json\"\n ```"} +{"text_chunk": "Next steps\n- Try the example here."} +{"text_chunk": "Distribute flow as executable app\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nWe are going to use the web-classification as\nan example to show how to distribute flow as executable app with Pyinstaller.\n\n\nPlease ensure that you have installed all the required dependencies. You can refer to the \"Prerequisites\" section in the README of the web-classification for a comprehensive list of prerequisites and installation instructions. And we recommend you to add a `requirements.txt` to indicate all the required dependencies for each flow. \n\nPyinstaller is a popular tool used for converting Python applications into standalone executables. It allows you to package your Python scripts into a single executable file, which can be run on a target machine without requiring the Python interpreter to be installed.\nStreamlit is an open-source Python library used for creating web applications quickly and easily. It's designed for data scientists and engineers who want to turn data scripts into shareable web apps with minimal effort.\nWe use Pyinstaller to package the flow and Streamlit to create custom web apps. Prior to distributing the workflow, kindly ensure that you have installed them."} +{"text_chunk": "Build a flow as executable format\nNote that all dependent connections must be created before building as executable.\n```bash"} +{"text_chunk": "create connection if not created before\npf connection create --file ../../../examples/connections/azure_openai.yml --set api_key= api_base= --name open_ai_connection\n```\n\nUse the command below to build a flow as executable format:\n```bash\npf flow build --source --output --format executable\n```"} +{"text_chunk": "Executable format folder structure\n\nExported files & its dependencies are located in the same folder. The structure is as below:\n- flow: the folder contains all the flow files.\n- connections: the folder contains yaml files to create all related connections.\n- app.py: the entry file is included as the entry point for the bundled application.\n- app.spec: the spec file tells PyInstaller how to process your script.\n- main.py: it will start streamlit service and be called by the entry file.\n- settings.json: a json file to store the settings of the executable application.\n- build: a folder contains various log and working files.\n- dist: a folder contains the executable application.\n- README.md: Simple introduction of the files."} +{"text_chunk": "A template script of the entry file\nPyInstaller reads a spec file or Python script written by you. It analyzes your code to discover every other module and library your script needs in order to execute. Then it collects copies of all those files, including the active Python interpreter, and puts them with your script in a single folder, or optionally in a single executable file. \n\nWe provide a Python entry script named `app.py` as the entry point for the bundled app, which enables you to serve a flow folder as an endpoint.\n\n```python\nimport os\nimport sys\n\nfrom promptflow._cli._pf._connection import create_connection\nfrom streamlit.web import cli as st_cli\nfrom streamlit.runtime import exists\n\nfrom main import start\n\ndef is_yaml_file(file_path):\n _, file_extension = os.path.splitext(file_path)\n return file_extension.lower() in ('.yaml', '.yml')\n\ndef create_connections(directory_path) -> None:\n for root, dirs, files in os.walk(directory_path):\n for file in files:\n file_path = os.path.join(root, file)\n if is_yaml_file(file_path):\n create_connection(file_path)\n\n\nif __name__ == \"__main__\":\n create_connections(os.path.join(os.path.dirname(__file__), \"connections\"))\n if exists():\n start()\n else:\n main_script = os.path.join(os.path.dirname(__file__), \"main.py\")\n sys.argv = [\"streamlit\", \"run\", main_script, \"--global.developmentMode=false\"]\n st_cli.main(prog_name=\"streamlit\")\n\n```"} +{"text_chunk": "A template script of the spec file\nThe spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.\n\nTo streamline this process, we offer a `app.spec` spec file that bundles the application into a single file. For additional information on spec files, you can refer to the Using Spec Files. Please replace `streamlit_runtime_interpreter_path` with the path of streamlit runtime interpreter in your environment.\n\n```spec"} +{"text_chunk": "-*- mode: python ; coding: utf-8 -*-\nfrom PyInstaller.utils.hooks import collect_data_files\nfrom PyInstaller.utils.hooks import copy_metadata\n\ndatas = [('connections', 'connections'), ('flow', 'flow'), ('settings.json', '.'), ('main.py', '.'), ('{{streamlit_runtime_interpreter_path}}', './streamlit/runtime')]\ndatas += collect_data_files('streamlit')\ndatas += copy_metadata('streamlit')\ndatas += collect_data_files('keyrings.alt', include_py_files=True)\ndatas += copy_metadata('keyrings.alt')\ndatas += collect_data_files('streamlit_quill')\n\nblock_cipher = None\n\n\na = Analysis(\n ['app.py', 'main.py'],\n pathex=[],\n binaries=[],\n datas=datas,\n hiddenimports=['bs4'],\n hookspath=[],\n hooksconfig={},\n runtime_hooks=[],\n excludes=[],\n win_no_prefer_redirects=False,\n win_private_assemblies=False,\n cipher=block_cipher,\n noarchive=False,\n)\npyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)\n\nexe = EXE(\n pyz,\n a.scripts,\n a.binaries,\n a.zipfiles,\n a.datas,\n [],\n name='app',\n debug=False,\n bootloader_ignore_signals=False,\n strip=False,\n upx=True,\n upx_exclude=[],\n runtime_tmpdir=None,\n console=True,\n disable_windowed_traceback=False,\n argv_emulation=False,\n target_arch=None,\n codesign_identity=None,\n entitlements_file=None,\n)\n```"} +{"text_chunk": "The bundled application using Pyinstaller\nOnce you've build a flow as executable format following Build a flow as executable format.\nIt will create two folders named `build` and `dist` within your specified output directory, denoted as . The `build` folder houses various log and working files, while the `dist` folder contains the `app` executable application."} +{"text_chunk": "Connections\nIf the service involves connections, all related connections will be exported as yaml files and recreated in the executable package.\nSecrets in connections won't be exported directly. Instead, we will export them as a reference to environment variables:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\ntype: open_ai\nname: open_ai_connection\nmodule: promptflow.connections\napi_key: ${env:OPEN_AI_CONNECTION_API_KEY} # env reference\n```"} +{"text_chunk": "Test the endpoint\nFinally, You can distribute the bundled application `app` to other people. They can execute your program by double clicking the executable file, e.g. `app.exe` in Windows system or running the binary file, e.g. `app` in Linux system. \n\nThe development server has a built-in web page they can use to test the flow by opening 'http://localhost:8501' in the browser. The expected result is as follows: if the flow served successfully, the process will keep alive until it is killed manually.\n\nTo your users, the app is self-contained. They do not need to install any particular version of Python or any modules. They do not need to have Python installed at all.\n\n**Note**: The executable generated is not cross-platform. One platform (e.g. Windows) packaged executable can't run on others (Mac, Linux)."} +{"text_chunk": "Known issues\n1. Note that Python 3.10.0 contains a bug making it unsupportable by PyInstaller. PyInstaller will also not work with beta releases of Python 3.13."} +{"text_chunk": "Next steps\n- Try the example here"} +{"text_chunk": "Develop chat flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a chat flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema."} +{"text_chunk": "Flow input data\n\nThe most important elements that differentiate a chat flow from a standard flow are **chat input** and **chat history**. A chat flow can have multiple inputs, but **chat history** and **chat input** are required inputs in chat flow.\n\n- **Chat Input**: Chat input refers to the messages or queries submitted by users to the chatbot. Effectively handling chat input is crucial for a successful conversation, as it involves understanding user intentions, extracting relevant information, and triggering appropriate responses.\n\n- **Chat History**: Chat history is the record of all interactions between the user and the chatbot, including both user inputs and AI-generated outputs. Maintaining chat history is essential for keeping track of the conversation context and ensuring the AI can generate contextually relevant responses. Chat history is a special type of chat flow input, that stores chat messages in a structured format.\n \n An example of chat history:\n ```python\n [\n {\"inputs\": {\"question\": \"What types of container software there are?\"}, \"outputs\": {\"answer\": \"There are several types of container software available, including: Docker, Kubernetes\"}},\n {\"inputs\": {\"question\": \"What's the different between them?\"}, \"outputs\": {\"answer\": \"The main difference between the various container software systems is their functionality and purpose. Here are some key differences between them...\"}},\n ] \n ```\n\nYou can set **is_chat_input**/**is_chat_history** to **true** to add chat_input/chat_history to the chat flow.\n```yaml\ninputs:\n chat_history:\n type: list\n is_chat_history: true\n default: []\n question:\n type: string\n is_chat_input: true\n default: What is ChatGPT?\n```\n\n\nFor more information see develop the flow using different tools."} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc.\n\nFor more information see develop the flow using different tools."} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface.\n\nFor more information see chain your flow."} +{"text_chunk": "Set flow output\n\n**Chat output** is required output in the chat flow. It refers to the AI-generated messages that are sent to the user in response to their inputs. Generating contextually appropriate and engaging chat outputs is vital for a positive user experience.\n\nYou can set **is_chat_output** to **true** to add chat_output to the chat flow.\n\n```yaml\noutputs:\n answer:\n type: string\n reference: ${chat.output}\n is_chat_output: true\n```"} +{"text_chunk": "Develop evaluation flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe evaluation flow is a flow to test/evaluate the quality of your LLM application (standard/chat flow). It usually runs on the outputs of standard/chat flow, and compute key metrics that can be used to determine whether the standard/chat flow performs well. See Flows for more information.\n\nBefore proceeding with this document, it is important to have a good understanding of the standard flow. Please make sure you have read Develop standard flow, since they share many common features and these features won't be repeated in this doc, such as:\n- `Inputs/Outputs definition`\n- `Nodes`\n- `Chain nodes in a flow`\n\nWhile the evaluation flow shares similarities with the standard flow, there are some important differences that set it apart. The main distinctions are as follows:\n- `Inputs from an existing run`: The evaluation flow contains inputs that are derived from the outputs of the standard/chat flow. These inputs are used for evaluation purposes.\n- `Aggregation node`: The evaluation flow contains one or more aggregation nodes, where the actual evaluation takes place. These nodes are responsible for computing metrics and determining the performance of the standard/chat flow."} +{"text_chunk": "Evaluation flow example\n\nIn this guide, we use eval-classification-accuracy flow as an example of the evaluation flow. This is a flow illustrating how to evaluate the performance of a classification flow. It involves comparing each prediction to the groundtruth and assigns a `Correct` or `Incorrect` grade, and aggregating the results to produce metrics such as `accuracy`, which reflects how good the system is at classifying the data."} +{"text_chunk": "Flow inputs\n\nThe flow `eval-classification-accuracy` contains two inputs:\n\n```yaml\ninputs:\n groundtruth:\n type: string\n description: Groundtruth of the original question, it's the correct label that you hope your standard flow could predict.\n default: APP\n prediction:\n type: string\n description: The actual predicted outputs that your flow produces.\n default: APP\n```\n\nAs evident from the inputs description, the evaluation flow requires two specific inputs: \n- `groundtruth`: This input represents the actual or expected values against which the performance of the standard/chat flow will be evaluated.\n- `prediction`: The prediction input is derived from the outputs of another standard/chat flow. It contains the predicted values generated by the standard/chat flow, which will be compared to the groundtruth values during the evaluation process.\n\nFrom the definition perspective, there is no difference compared with adding an input/output in a `standard/chat flow`. However when running an evaluation flow, you may need to specify the data source from both data file and flow run outputs. For more details please refer to Run and evaluate a flow."} +{"text_chunk": "Aggregation node\n\n\nBefore introducing the aggregation node, let's see what a regular node looks like, we use node `grade` in the example flow for instance:\n\n```yaml\n- name: grade\n type: python\n source:\n type: code\n path: grade.py\n inputs:\n groundtruth: ${inputs.groundtruth}\n prediction: ${inputs.prediction}\n```\n\nIt takes both `groundtruth` and `prediction` from the flow inputs, compare them in the source code to see if they match:\n\n```python\nfrom promptflow import tool\n\n@tool\ndef grade(groundtruth: str, prediction: str):\n return \"Correct\" if groundtruth.lower() == prediction.lower() else \"Incorrect\"\n```\n\nWhen it comes to an `aggregation node`, there are two key distinctions that set it apart from a regular node:\n1. It has an attribute `aggregation` set to be `true`.\n\n```yaml\n- name: calculate_accuracy\n type: python\n source:\n type: code\n path: calculate_accuracy.py\n inputs:\n grades: ${grade.output}\n aggregation: true # Add this attribute to make it an aggregation node\n```\n\n2. Its source code accepts a `List` type parameter which is a collection of the previous regular node's outputs.\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef calculate_accuracy(grades: List[str]):\n result = []\n for index in range(len(grades)):\n grade = grades[index]\n result.append(grade)\n\n # calculate accuracy for each variant\n accuracy = round((result.count(\"Correct\") / len(result)), 2)\n log_metric(\"accuracy\", accuracy)\n\n return result\n```\n\nThe parameter `grades` in above function, contains all results that are produced by the regular node `grade`. Assuming the referred standard flow run has 3 outputs:\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Channel\"}\n{\"prediction\": \"Academic\"}\n```\n\n\n And we provides a data file like this:\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Channel\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nThen the `grades` value would be `[\"Correct\", \"Correct\", \"Incorrect\"]`, and the final accuracy is `0.67`. \n\nThis example provides a straightforward demonstration of how to evaluate the classification flow. Once you have a solid understanding of the evaluation mechanism, you can customize and design your own evaluation method to suit your specific needs."} +{"text_chunk": "More about the list parameter\n\nWhat if the number of referred standard flow run outputs does not match the provided data file? We know that a standard flow can be executed against multiple line data and some of them could fail while others succeed. Consider the same standard flow run mentioned in above example but the `2nd` line run has failed, thus we have below run outputs:\n\n\n```json\n{\"prediction\": \"App\"}\n{\"prediction\": \"Academic\"}\n```\n\nThe promptflow flow executor has the capability to recognize the index of the referred run's outputs and extract the corresponding data from the provided data file. This means that during the execution process, even if the same data file is provided(3 lines), only the specific data mentioned below will be processed:\n\n ```json\n{\"groundtruth\": \"App\"}\n{\"groundtruth\": \"Wiki\"}\n```\n\nIn this case, the `grades` value would be `[\"Correct\", \"Incorrect\"]` and the accuracy is `0.5`."} +{"text_chunk": "How to set aggregation node in VS Code Extention\n\n\n!img"} +{"text_chunk": "How to log metrics\n:::{admonition} Limitation\nYou can only log metrics in an `aggregation node`, otherwise the metric will be ignored.\n:::\nPromptflow supports logging and tracking experiments using `log_metric` function. A metric is a key-value pair that records a single float measure. In a python node, you can log a metric with below code: \n\n\n```python\nfrom typing import List\nfrom promptflow import log_metric, tool\n\n@tool\ndef example_log_metrics(grades: List[str]):\n # this node is an aggregation node so it accepts a list of grades\n metric_key = \"accuracy\"\n metric_value = round((grades.count(\"Correct\") / len(result)), 2)\n log_metric(metric_key, metric_value)\n```\n\nAfter the run is completed, you can run `pf run show-metrics -n ` to see the metrics.\n\n!img"} +{"text_chunk": "Develop standard flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, you can learn how to develop a standard flow by writing a flow yaml from scratch. You can \nfind additional information about flow yaml schema in Flow YAML Schema."} +{"text_chunk": "Flow input data\nThe flow input data is the data that you want to process in your flow. \n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a flow input in inputs section of flow yaml.\n```yaml\ninputs:\n url:\n type: string\n default: https://www.microsoft.com/en-us/d/xbox-wireless-controller-stellar-shift-special-edition/94fbjc7h0h6h\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen unfolding Inputs section in the authoring page, you can set and view your flow inputs, including input schema (name and type), \nand the input value.\n\n!flow_input\n:::\n\n::::\nFor Web Classification sample as shown the screenshot above, the flow input is an url of string type.\nFor more input types in a python tool, please refer to Input types."} +{"text_chunk": "Develop the flow using different tools\nIn one flow, you can consume different kinds of tools. We now support built-in tool like \nLLM, Python and \nPrompt and \nthird-party tool like Serp API, \nVector Search, etc."} +{"text_chunk": "Add tool as your need\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add a tool node in nodes section of flow yaml. For example, yaml below shows how to add a Python tool node in the flow.\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nBy selecting the tool card on the very top, you'll add a new tool node to flow.\n\n!add_tool\n:::\n\n::::"} +{"text_chunk": "Edit tool\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can edit the tool by simply opening the source file and making edits. For example, we provide a simple Python tool code below.\n\n```python\nfrom promptflow import tool"} +{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(input1: str) -> str:\n return 'hello ' + input1\n```\n\nWe also provide an LLM tool prompt below.\n\n```jinja\nPlease summarize the following text in one paragraph. 100 words.\nDo not add any information that is not in the text.\nText: {{text}}\nSummary:\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nWhen a new tool node is added to flow, it will be appended at the bottom of flatten view with a random name by default. \nAt the top of each tool node card, there's a toolbar for adjusting the tool node. You can move it up or down, you can delete or rename it too.\nFor a python tool node, you can edit the tool code by clicking the code file. For a LLM tool node, you can edit the \ntool prompt by clicking the prompt file and adjust input parameters like connection, api and etc.\n!edit_tool\n:::\n\n::::"} +{"text_chunk": "Create connection\nPlease refer to the Create necessary connections for details."} +{"text_chunk": "Chain your flow - link nodes together\nBefore linking nodes together, you need to define and expose an interface."} +{"text_chunk": "Define LLM node interface\nLLM node has only one output, the completion given by LLM provider.\n\nAs for inputs, we offer a templating strategy that can help you create parametric prompts that accept different input \nvalues. Instead of fixed text, enclose your input name in `{{}}`, so it can be replaced on the fly. We use Jinja as our \ntemplating language. For example:\n\n```jinja\nYour task is to classify a given url into one of the following types:\nMovie, App, Academic, Channel, Profile, PDF or None based on the text content information.\nThe classification will be based on the url, the webpage text content summary, or both.\n\nHere are a few examples:\n{% for ex in examples %}\nURL: {{ex.url}}\nText content: {{ex.text_content}}\nOUTPUT:\n{\"category\": \"{{ex.category}}\", \"evidence\": \"{{ex.evidence}}\"}\n\n{% endfor %}\n\nFor a given URL : {{url}}, and text content: {{text_content}}.\nClassify above url to complete the category and indicate evidence.\nOUTPUT:\n```"} +{"text_chunk": "Define Python node interface\nPython node might have multiple inputs and outputs. Define inputs and outputs as shown below. \nIf you have multiple outputs, remember to make it a dictionary so that the downstream node can call each key separately.\nFor example:\n\n```python\nimport json\nfrom promptflow import tool\n\n@tool\ndef convert_to_dict(input_str: str, input_str2: str) -> dict:\n try:\n print(input_str2)\n return json.loads(input_str)\n except Exception as e:\n print(\"input is not valid, error: {}\".format(e))\n return {\"category\": \"None\", \"evidence\": \"None\"}\n```"} +{"text_chunk": "Link nodes together\nAfter the interface is defined, you can use:\n\n- ${inputs.key} to link with flow input.\n- ${upstream_node_name.output} to link with single-output upstream node.\n- ${upstream_node_name.output.key} to link with multi-output upstream node.\n\nBelow are common scenarios for linking nodes together."} +{"text_chunk": "Scenario 1 - Link LLM node with flow input and single-output upstream node\nAfter you add a new LLM node and edit the prompt file like Define LLM node interface, \nthree inputs called `url`, `examples` and `text_content` are created in inputs section.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link the LLM node input with flow input by `${inputs.url}`. \nAnd you can link `examples` to the upstream `prepare_examples` node and `text_content` to the `summarize_text_content` node \nby `${prepare_examples.output}` and `${summarize_text_content.output}`. \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n url: ${inputs.url} # Link with flow input\n examples: ${prepare_examples.output} # Link LLM node with single-output upstream node\n text_content: ${summarize_text_content.output} # Link LLM node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${inputs.url}`, `${prepare_examples.output}` and `${summarize_text_content.output}`, then \nyou'll see in the graph view that the newly created LLM node is linked to the flow input, upstream `prepare_examples` and `summarize_text_content` node. \n\n!link_llm_with_flow_input_single_output_node\n:::\n\n::::\nWhen running the flow, the `url` input of the node will be replaced by flow input on the fly, and the `examples` and \n`text_content` input of the node will be replaced by `prepare_examples` and `summarize_text_content` node output on the fly."} +{"text_chunk": "Scenario 2 - Link LLM node with multi-output upstream node\nSuppose we want to link the newly created LLM node with `covert_to_dict` Python node whose output is a dictionary with two keys: `category` and `evidence`.\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can link `examples` to the `evidence` output of upstream `covert_to_dict` node by `${convert_to_dict.output.evidence}` like below: \n```yaml\n- name: classify_with_llm\n type: llm\n source:\n type: code\n path: classify_with_llm.jinja2\n inputs:\n deployment_name: text-davinci-003\n suffix: \"\"\n max_tokens: 128\n temperature: 0.2\n top_p: 1\n echo: false\n presence_penalty: 0\n frequency_penalty: 0\n best_of: 1\n text_content: ${convert_to_dict.output.evidence} # Link LLM node with multi-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nIn the value drop-down, select `${convert_to_dict.output}`, then manually append `evidence`, then you'll see in the graph \nview that the newly created LLM node is linked to the upstream `convert_to_dict node`.\n\n!link_llm_with_multi_output_node\n:::\n::::\nWhen running the flow, the `text_content` input of the node will be replaced by `evidence` value from `convert_to_dict node` output dictionary on the fly."} +{"text_chunk": "Scenario 3 - Link Python node with upstream node/flow input\nAfter you add a new Python node and edit the code file like Define Python node interface], \ntwo inputs called `input_str` and `input_str2` are created in inputs section. The linkage is the same as LLM node, \nusing `${flow.input_name}` to link with flow input or `${upstream_node_name.output}` to link with upstream node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n```yaml\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs:\n input_str: ${inputs.url} # Link Python node with flow input\n input_str2: ${fetch_text_content_from_url.output} # Link Python node with single-output upstream node\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n!link_python_with_flow_node_input\n:::\n\n::::\nWhen running the flow, the `input_str` input of the node will be replaced by flow input on the fly and the `input_str2` \ninput of the node will be replaced by `fetch_text_content_from_url` node output dictionary on the fly."} +{"text_chunk": "Set flow output\nWhen the flow is complicated, instead of checking outputs on each node, you can set flow output and check outputs of \nmultiple nodes in one place. Moreover, flow output helps:\n\n- Check bulk test results in one single table.\n- Define evaluation interface mapping.\n- Set deployment response schema.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nYou can add flow outputs in outputs section of flow yaml . The linkage is the same as LLM node, \nusing `${convert_to_dict.output.category}` to link `category` flow output with with `category` value of upstream node \n`convert_to_dict`.\n\n```yaml\noutputs:\n category:\n type: string\n reference: ${convert_to_dict.output.category}\n evidence:\n type: string\n reference: ${convert_to_dict.output.evidence}\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\nFirst define flow output schema, then select in drop-down the node whose output you want to set as flow output. \nSince `convert_to_dict` has a dictionary output with two keys: `category` and `evidence`, you need to manually append \n`category` and `evidence` to each. Then run flow, after a while, you can check flow output in a table.\n\n!flow_output\n:::\n\n::::"} +{"text_chunk": "Referencing external files/folders in a flow\n\nSometimes, pre-existing code assets are essential for the flow reference. In most cases, you can accomplish this by importing a Python package into your flow. However, if a Python package is not available or it is heavy to create a package, you can still reference external files or folders located outside of the current flow folder by using our **additional includes** feature in your flow configuration.\n\nThis feature provides an efficient mechanism to list relative file or folder paths that are outside of the flow folder, integrating them seamlessly into your flow.dag.yaml. For example:\n\n```yaml\nadditional_includes:\n- ../web-classification/classify_with_llm.jinja2\n- ../web-classification/convert_to_dict.py\n- ../web-classification/fetch_text_content_from_url.py\n- ../web-classification/prepare_examples.py\n- ../web-classification/summarize_text_content.jinja2\n- ../web-classification/summarize_text_content__variant_1.jinja2\n```\n\nYou can add this field `additional_includes` into the flow.dag.yaml. The value of this field is a list of the **relative file/folder path** to the flow folder.\n\nJust as with the common definition of the tool node entry, you can define the tool node entry in the flow.dag.yaml using only the file name, eliminating the need to specify the relative path again. For example:\n\n```yaml\nnodes:\n- name: fetch_text_content_from_url\n type: python\n source:\n type: code\n path: fetch_text_content_from_url.py\n inputs:\n url: ${inputs.url}\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n```\n\nThe entry file \"fetch_text_content_from_url.py\" of the tool node \"fetch_text_content_from_url\" is located in \"../web-classification/fetch_text_content_from_url.py\", as specified in the additional_includes field. The same applies to the \"summarize_text_content\" tool nodes.\n\n> **Note**:\n>\n> 1. If you have two files with the same name located in different folders specified in the `additional_includes` field, and the file name is also specified as the entry of a tool node, the system will reference the **last one** it encounters in the `additional_includes` field.\n> > 1. If you have a file in the flow folder with the same name as a file specified in the `additional_includes` field, the system will prioritize the file listed in the `additional_includes` field.\nTake the following YAML structure as an example:\n\n```yaml\nadditional_includes:\n- ../web-classification/prepare_examples.py\n- ../tmp/prepare_examples.py\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n- name: prepare_examples\n type: python\n source:\n type: code\n path: prepare_examples.py\n inputs: {}\n``` \n\nIn this case, the system will use \"../tmp/prepare_examples.py\" as the entry file for the tool node \"prepare_examples\". Even if there is a file named \"prepare_examples.py\" in the flow folder, the system will still use the file \"../tmp/prepare_examples.py\" specified in the `additional_includes` field.\n\n> Tips:\n> The additional includes feature can significantly streamline your workflow by eliminating the need to manually handle these references.\n> 1. To get a hands-on experience with this feature, practice with our sample flow-with-additional-includes.\n> 1. You can learn more about How the 'additional includes' flow operates during the transition to the cloud."} +{"text_chunk": "Adding a tool icon\nA tool icon serves as a graphical representation of your tool in the user interface (UI). Follow this guidance to add a custom tool icon when developing your own tool package.\n\nAdding a custom tool icon is optional. If you do not provide one, the system uses a default icon."} +{"text_chunk": "Prerequisites\n\n- Please ensure that your Prompt flow for VS Code is updated to version 1.4.2 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later.\n- Create a tool package as described in Create and Use Tool Package.\n- Prepare custom icon image that meets these requirements:\n\n - Use PNG, JPG or BMP format.\n - 16x16 pixels to prevent distortion when resizing.\n - Avoid complex images with lots of detail or contrast, as they may not resize well. \n\n See this example as a reference."} +{"text_chunk": "Add tool icon with _icon_ parameter"} +{"text_chunk": "Initialize a package tool with icon\nYou can use pf tool init to initialize a package tool with icon:\n```bash\npf tool init --package --tool --set icon=\n```\n\nPF CLI will copy the icon file to the folder `/icons/` and generate a tool script in the package. The tool icon will be configured in the tool script. Here we use an existing tool as an example, the code is as follows:\n```python\nfrom pathlib import Path\n\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n icon=Path(__file__).parent.parent / \"icons\" / \"custom-tool-icon.png\"\n)\ndef my_tool(connection: CustomConnection, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```\n\nThe folder structure of the generated tool package is as follows:\n```\n\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u251c\u2500\u2500\u2500icons\n\u2502 \n\u2502\n\u2514\u2500\u2500\u2500\n .py\n utils.py\n __init__.py\n```"} +{"text_chunk": "Verify the tool icon in VS Code extension\nFollow steps to use your tool from VS Code extension. Your tool displays with the custom icon: \n!custom-tool-with-icon-in-extension"} +{"text_chunk": "FAQ\nYes, you could run below command under the root folder to generate a data URI for your custom tool icon. Make sure the output file has an `.html` extension.\n```\npython \\tool\\convert_image_to_data_url.py --image-path -o \n```\nFor example:\n```\npython D:\\proj\\github\\promptflow\\scripts\\tool\\convert_image_to_data_url.py --image-path D:\\proj\\github\\promptflow\\examples\\tools\\tool-package-quickstart\\my_tool_package\\icons\\custom-tool-icon.png -o output.html\n```\nThe content of `output.html` looks like the following, open it in a web browser to preview the icon.\n```html\n\n\n\n\n\n```"} +{"text_chunk": "Can I add a tool icon to an existing tool package\n\nYou can follow these steps to add an icon to an existing package tool:\n1. Copy the icon image to the package folder.\n2. Configure the icon for the tool.\n\n In the tool script, add the `icon` parameter to the decorator method `@tool`, and the parameter value is the `icon path`. The code is as follows:\n ```python\n from promptflow import tool\n\n @tool(name=\"tool_name\", icon=)\n def tool_func(input_text: str) -> str:\n # Tool logic\n pass\n ```\n3. Update `MANIFEST.in` in the package folder.\n\n This file is used to determine which files to include in the distribution of the project. You need to add the icon path relative to the package folder to this file.\n ```\n include \n ```"} +{"text_chunk": "Can I add tool icons for dark and light mode separately?\nYes, you can add the tool icon data to the tool code as follows:\n```python\nfrom promptflow import tool\n\n@tool(name=\"tool_name\", icon_dark=, icon_light=)\ndef tool_func(input_text: str) -> str:\n # Tool logic\n pass\n```\n\nOr run the command below in your tool project directory to automatically generate tool code, use _--icon_light_ to add a custom tool icon for the light mode and use _--icon_dark_ to add a custom tool icon for the dark mode:\n```python\npf tool init --tool --set icon_dark= icon_light=\n```\n\nNote: Both light and dark icons are optional. If you set either a light or dark icon, it will be used in its respective mode, and the system default icon will be used in the other mode."} +{"text_chunk": "Adding category and tags for tool\n\nThis document is dedicated to guiding you through the process of categorizing and tagging your tools for optimal organization and efficiency. Categories help you organize your tools into specific folders, making it much easier to find what you need. Tags, on the other hand, work like labels that offer more detailed descriptions. They enable you to quickly search and filter tools based on specific characteristics or functions. By using categories and tags, you'll not only tailor your tool library to your preferences but also save time by effortlessly finding the right tool for any task.\n\n| Attribute | Type | Required | Description |\n| --------- | ---- | -------- | ----------- |\n| category | str | No | Organizes tools into folders by common features. |\n| tags | dict | No | Offers detailed, searchable descriptions of tools through key-value pairs. |\n\n**Important Notes:**\n- Tools without an assigned category will be listed in the root folder.\n- Tools lacking tags will display an empty tags field."} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later.\n- Please install promptflow package and ensure that its version is 1.1.0 or later."} +{"text_chunk": "How to add category and tags for a tool\n\nYou can use pf tool init to initialize a package tool with category and tags:\n```python\npf tool init --package --tool --set category= tags=\n\n```\n\nHere, we use an example to show the categories and tags of the tool after initialization. Assume that the user executes this command:\n```python\npf tool init --tool my_tool --set name=\"My First Tool\" description=\"This is my first tool\" category=\"test_tool\" tags=\"{'tag1':'value1','tag2':'value2'}\"\n```\nThe generated tool script is as follows, where category and tags have been configured on the tool:\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection\n\n\n@tool(\n name=\"My First Tool\",\n description=\"This is my first tool\",\n category=\"test_tool\",\n tags={\"tag1\": \"value1\", \"tag2\": \"value2\"},\n)\ndef my_tool(self, input_text: str) -> str:\n # Replace with your tool code.\n # Usually connection contains configs to connect to an API.\n # Use CustomConnection is a dict. You can use it like: connection.api_key, connection.api_base\n # Not all tools need a connection. You can remove it if you don't need it.\n return \"Hello \" + input_text\n```"} +{"text_chunk": "Tool with category and tags experience in VS Code extension\nFollow the steps to use your tool via the VS Code extension.\n- Experience in the tool tree\n!category_and_tags_in_tool_tree\n\n- Experience in the tool list\nBy clicking `More` in the visual editor, you can view your tools along with their category and tags:\n!category_and_tags_in_tool_list\nFurthermore, you have the option to search or filter tools based on tags:\n!filter_tools_by_tag"} +{"text_chunk": "FAQ\nCustomer can configure category and tags directly on the tool script, as shown in the following code:\n```python\n@tool(\n name=\"tool_name\",\n description=\"This is tool_name tool\",\n category=,\n tags=,\n)\ndef tool_name(input_text: str) -> str:\n # tool logic\n pass\n```"} +{"text_chunk": "Create and use tool package\nIn this document, we will guide you through the process of developing your own tool package, offering detailed steps and advice on how to utilize your creation.\n\nThe custom tool is the prompt flow tool developed by yourself. If you find it useful, you can follow this guidance to make it a tool package. This will enable you to conveniently reuse it, share it with your team, or distribute it to anyone in the world.\n\nAfter successful installation of the package, your custom \"tool\" will show up in VSCode extension as below: \n!custom-tool-list"} +{"text_chunk": "Create your own tool package\nYour tool package should be a python package. To try it quickly, just use my-tools-package 0.0.1 and skip this section."} +{"text_chunk": "Prerequisites\nCreate a new conda environment using python 3.9 or 3.10. Run below command to install PromptFlow dependencies:\n```\npip install promptflow\n```"} +{"text_chunk": "Create custom tool package\nYou can use pf tool init to initialize a package tool in current folder:\n\n```bash\npf tool init --package --tool \n\n```\nFor example:\n```bash\npf tool init --package hello_world --tool hello_world_tool\n```\nThis auto-generated script will create one tool for you. The parameters _destination_ and _package-name_ are mandatory. The parameters _tool-name_ and _function-name_ are optional. If left unfilled, the _tool-name_ will default to _hello_world_tool_, and the _function-name_ will default to _tool-name_.\n\nThe command will generate the tool project as follows with one tool `hello_world_tool.py` in it:\n\n```\nhello_world/\n\u2502 MANIFEST.in\n\u2502 README.md\n\u2502 setup.py\n\u2502\n\u2514\u2500\u2500\u2500hello_world/\n hello_world_tool.py\n utils.py\n __init__.py\n```\n\n```The points outlined below explain the purpose of each folder/file in the package. If your aim is to develop multiple tools within your package, please make sure to closely examine point 2 and 5.```\n\n1. **hello_world**: This is the source directory. All of your project's source code should be placed in this directory.\n2. **hello_world/hello_world**: This directory contains the individual tools for your project. Your tool package can contain either one tool or many tools. When adding a new tool, you should create another *.py under this folder.\n3. **hello-world/hello_world/hello_world_tool.py**: Develop your tool within the def function. Use the `@tool` decorator to identify the function as a tool.\n > !Note] There are two ways to write a tool. The default and recommended way is the function implemented way. You can also use the class implementation way, referring to [my_tool_2.py as an example.\n4. **hello-world/hello_world/utils.py**: This file implements the tool list method, which collects all the tools defined. It is required to have this tool list method, as it allows the User Interface (UI) to retrieve your tools and display them within the UI.\n > [!Note] There's no need to create your own list method if you maintain the existing folder structure. You can simply use the auto-generated list method provided in the `utils.py` file.\n7. **MANIFEST.in**: This file is used to determine which files to include in the distribution of the project.\n > [!Note] There's no need to update this file if you maintain the existing folder structure.\n8. **setup.py**: This file contains metadata about your project like the name, version, author, and more. Additionally, the entry point is automatically configured for you by `pf tool init`. In Python, configuring the entry point in `setup.py` helps establish the primary execution point for a package, streamlining its integration with other software. \n\n The `package_tools` entry point together with the tool list method are used to retrieve all the tools and display them in the UI.\n ```python\n entry_points={\n \"package_tools\": [\" = :\"],\n },\n ```\n > [!Note] There's no need to update this file if you maintain the existing folder structure."} +{"text_chunk": "Build and share the tool package\n Execute the following command in the tool package root directory to build your tool package:\n ```\n python setup.py sdist bdist_wheel\n ```\n This will generate a tool package `-0.0.1.tar.gz` and corresponding `whl file` inside the `dist` folder.\n\n Create an account on PyPI if you don't already have one, and install `twine` package by running `pip install twine`.\n\n Upload your package to PyPI by running `twine upload dist/*`, this will prompt you for your Pypi username and password, and then upload your package on PyPI. Once your package is uploaded to PyPI, others can install it using pip by running `pip install your-package-name`. Make sure to replace `your-package-name` with the name of your package as it appears on PyPI.\n\n If you only want to put it on Test PyPI, upload your package by running `twine upload --repository-url https://test.pypi.org/legacy/ dist/*`. Once your package is uploaded to Test PyPI, others can install it using pip by running `pip install --index-url https://test.pypi.org/simple/ your-package-name`."} +{"text_chunk": "Use your tool from VSCode Extension\n* Step1: Install Prompt flow for VS Code extension. \n\n* Step2: Go to terminal and install your tool package in conda environment of the extension. Assume your conda env name is `prompt-flow`.\n ```\n (local_test) PS D:\\projects\\promptflow\\tool-package-quickstart> conda activate prompt-flow\n (prompt-flow) PS D:\\projects\\promptflow\\tool-package-quickstart> pip install .\\dist\\my_tools_package-0.0.1-py3-none-any.whl\n ``` \n\n* Step3: Go to the extension and open one flow folder. Click 'flow.dag.yaml' and preview the flow. Next, click `+` button and you will see your tools. You may need to reload the windows to clean previous cache if you don't see your tool in the list.\n!auto-list-tool-in-extension"} +{"text_chunk": "FAQs\nConfirm that configured the package tool correctly. Alternatively, you can test your tool package using the script below to ensure that you've configured the package tool entry point correctly.\n\n 1. Make sure to install the tool package in your conda environment before executing this script.\n 2. Create a python file anywhere and copy the content below into it.\n ```python\n import importlib\n import importlib.metadata\n\n def test():\n \"\"\"List all package tools information using the `package-tools` entry point.\n\n This function iterates through all entry points registered under the group \"package_tools.\"\n For each tool, it imports the associated module to ensure its validity and then prints\n information about the tool.\n\n Note:\n - Make sure your package is correctly packed to appear in the list.\n - The module is imported to validate its presence and correctness.\n\n Example of tool information printed:\n ----identifier\n {'module': 'module_name', 'package': 'package_name', 'package_version': 'package_version', ...}\n \"\"\"\n entry_points = importlib.metadata.entry_points()\n PACKAGE_TOOLS_ENTRY = \"package_tools\"\n if isinstance(entry_points, list):\n entry_points = entry_points.select(group=PACKAGE_TOOLS_ENTRY)\n else:\n entry_points = entry_points.get(PACKAGE_TOOLS_ENTRY, [])\n for entry_point in entry_points:\n list_tool_func = entry_point.load()\n package_tools = list_tool_func()\n\n for identifier, tool in package_tools.items():\n importlib.import_module(tool[\"module\"]) # Import the module to ensure its validity\n print(f\"----{identifier}\\n{tool}\")\n\n if __name__ == \"__main__\":\n test()\n ```\n 3. Run this script in your conda environment. This will return the metadata of all tools installed in your local environment, and you should verify that your tools are listed."} +{"text_chunk": "Why am I unable to upload package to PyPI?\n* Make sure that the entered username and password of your PyPI account are accurate.\n* If you encounter a `403 Forbidden Error`, it's likely due to a naming conflict with an existing package. You will need to choose a different name. Package names must be unique on PyPI to avoid confusion and conflicts among users. Before creating a new package, it's recommended to search PyPI (https://pypi.org/) to verify that your chosen name is not already taken. If the name you want is unavailable, consider selecting an alternative name or a variation that clearly differentiates your package from the existing one."} +{"text_chunk": "Advanced features\n- Add a Tool Icon \n- Add Category and Tags for Tool \n- Create and Use Your Own Custom Strong Type Connection \n- Customize an LLM Tool \n- Use File Path as Tool Input \n- Create a Dynamic List Tool Input \n- Create Cascading Tool Inputs"} +{"text_chunk": "Creating cascading tool inputs\n\nCascading input settings are useful when the value of one input field determines which subsequent inputs are shown. This makes the input process more streamlined, user-friendly, and error-free. This guide will walk through how to create cascading inputs for your tools."} +{"text_chunk": "Prerequisites\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.2.0+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} +{"text_chunk": "Create a tool with cascading inputs\nWe'll build out an example tool to show how cascading inputs work. The `student_id` and `teacher_id` inputs will be controlled by the value selected for the `user_type` input. Here's how to configure this in the tool code.\n\nDevelop the tool function, following the cascading inputs example. Key points:\n * Use the `@tool` decorator to mark the function as a tool.\n * Define `UserType` as an Enum class, as it accepts only a specific set of fixed values in this example.\n * Conditionally use inputs in the tool logic based on `user_type`.\n * Add `enabled_by` and `enabled_by_value` to control visibility of dependent inputs.\n * The `enabled_by` attribute specifies the input field, which must be an enum type, that controls the visibility of the dependent input field.\n * The `enabled_by_value` attribute defines the accepted enum values from the `enabled_by` field that will make this dependent input field visible.\n > Note: `enabled_by_value` takes a list, allowing multiple values to enable an input.\n\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass UserType(str, Enum):\n STUDENT = \"student\"\n TEACHER = \"teacher\"\n\n\n@tool(\n name=\"My Tool with Enabled By Value\",\n description=\"This is my tool with enabled by value\",\n input_settings={\n \"teacher_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.TEACHER]),\n \"student_id\": InputSetting(enabled_by=\"user_type\", enabled_by_value=[UserType.STUDENT]),\n }\n)\ndef my_tool(user_type: UserType, student_id: str = \"\", teacher_id: str = \"\") -> str:\n \"\"\"This is a dummy function to support enabled by feature.\n :param user_type: user type, student or teacher.\n :param student_id: student id.\n :param teacher_id: teacher id.\n :return: id of the user.\n If user_type is student, return student_id.\n If user_type is teacher, return teacher_id.\n \"\"\"\n if user_type == UserType.STUDENT:\n return student_id\n elif user_type == UserType.TEACHER:\n return teacher_id\n else:\n raise Exception(\"Invalid user.\")\n```"} +{"text_chunk": "Use the tool in VS Code\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. We have a demo flow you can try.\n\nBefore selecting a `user_type`, the `student_id` and `teacher_id` inputs are hidden. Once you pick the `user_type`, the corresponding input appears.\n!before_user_type_selected.png\n!after_user_type_selected_with_student.png\n!after_user_type_selected_with_teacher.png"} +{"text_chunk": "FAQs\nIf you are dealing with multiple levels of cascading inputs, you can effectively manage the dependencies between them by using the `enabled_by` and `enabled_by_value` attributes. For example:\n```python\nfrom enum import Enum\n\nfrom promptflow.entities import InputSetting\nfrom promptflow import tool\n\n\nclass EventType(str, Enum):\n CORPORATE = \"corporate\"\n PRIVATE = \"private\"\n\n\nclass CorporateTheme(str, Enum):\n SEMINAR = \"seminar\"\n TEAM_BUILDING = \"team_building\"\n\n\n@tool(\n name=\"My Tool with Multi-Layer Cascading Inputs\",\n description=\"This is my tool with multi-layer cascading inputs\",\n input_settings={\n \"corporate_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[EventType.CORPORATE]),\n \"seminar_location\": InputSetting(enabled_by=\"corporate_theme\", enabled_by_value=[CorporateTheme.SEMINAR]),\n \"private_theme\": InputSetting(enabled_by=\"event_type\", enabled_by_value=[CorporateTheme.PRIVATE]),\n }\n)\ndef my_tool(event_type: EventType, corporate_theme: CorporateTheme, seminar_location: str, private_theme: str) -> str:\n \"\"\"This is a dummy function to support enabled by feature.\"\"\"\n pass\n```\nInputs will be enabled in a cascading way based on selections."} +{"text_chunk": "Creating a dynamic list tool input\n\nTool input options can be generated on the fly using a dynamic list. Instead of having predefined static options, the tool author defines a request function that queries backends like APIs to retrieve real-time options. This enables flexible integration with various data sources to populate dynamic options. For instance, the function could call a storage API to list current files. Rather than a hardcoded list, the user sees up-to-date options when running the tool."} +{"text_chunk": "Prerequisites\n\n- Please make sure you have the latest version of Prompt flow for VS Code installed (v1.3.1+).\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} +{"text_chunk": "Create a tool input with dynamic listing"} +{"text_chunk": "Create a list function\n\nTo enable dynamic listing, the tool author defines a request function with the following structure:\n\n- Type: Regular Python function, can be in tool file or separate file\n- Input: Accepts parameters needed to fetch options\n- Output: Returns a list of option objects as `List[Dict[str, Union[str, int, float, list, Dict]]]`:\n - Required key:\n - `value`: Internal option value passed to tool function\n - Optional keys:\n - `display_value`: Display text shown in dropdown (defaults to `value`)\n - `hyperlink`: URL to open when option clicked\n - `description`: Tooltip text on hover\n\nThis function can make backend calls to retrieve the latest options, returning them in a standardized dictionary structure for the dynamic list. The required and optional keys enable configuring how each option appears and behaves in the tool input dropdown. See my_list_func as an example.\n\n```python\ndef my_list_func(prefix: str = \"\", size: int = 10, **kwargs) -> List[Dict[str, Union[str, int, float, list, Dict]]]:\n \"\"\"This is a dummy function to generate a list of items.\n\n :param prefix: prefix to add to each item.\n :param size: number of items to generate.\n :param kwargs: other parameters.\n :return: a list of items. Each item is a dict with the following keys:\n - value: for backend use. Required.\n - display_value: for UI display. Optional.\n - hyperlink: external link. Optional.\n - description: information icon tip. Optional.\n \"\"\"\n import random\n\n words = [\"apple\", \"banana\", \"cherry\", \"date\", \"elderberry\", \"fig\", \"grape\", \"honeydew\", \"kiwi\", \"lemon\"]\n result = []\n for i in range(size):\n random_word = f\"{random.choice(words)}{i}\"\n cur_item = {\n \"value\": random_word,\n \"display_value\": f\"{prefix}_{random_word}\",\n \"hyperlink\": f'https://www.bing.com/search?q={random_word}',\n \"description\": f\"this is {i} item\",\n }\n result.append(cur_item)\n\n return result\n```"} +{"text_chunk": "Configure a tool input with the list function\n\nIn `input_settings` section of tool, add following properties to the input that you want to make dynamic:\n\n- `DynamicList`:\n - `function`: Path to the list function (module_name.function_name).\n - `input_mapping`: Parameters to pass to the function, can reference other input values.\n- `allow_manual_entry`: Allow user to enter input value manually. Default to false.\n- `is_multi_select`: Allow user to select multiple values. Default to false.\n\nSee tool_with_dynamic_list_input.py as an example.\n\n```python\nfrom promptflow._core.tool import tool\nfrom promptflow.entities import InputSetting, DynamicList\n\n\ndynamic_list_setting = DynamicList(function=my_list_func, input_mapping={\"prefix\": \"input_prefix\"})\ninput_settings = {\n \"input_text\": InputSetting(\n dynamic_list=dynamic_list_setting,\n allow_manual_entry=True,\n is_multi_select=True\n )\n}\n\n\n@tool(\n name=\"My Tool with Dynamic List Input\",\n description=\"This is my tool with dynamic list input\",\n input_settings=input_settings\n)\ndef my_tool(input_text: list, input_prefix: str) -> str:\n return f\"Hello {input_prefix} {','.join(input_text)}\"\n```"} +{"text_chunk": "Use the tool in VS Code\n\nOnce you package and share your tool, you can use it in VS Code per the tool package guide. You could try `my-tools-package` for a quick test.\n\n```sh\npip install my-tools-package>=0.0.8\n```\n\n!dynamic list tool input options\n!dynamic list tool input selected\n\n> Note: If your dynamic list function call Azure APIs, you need to login to Azure and set default workspace. Otherwise, the tool input will be empty and you can't select anything. See FAQs for more details."} +{"text_chunk": "FAQs"} +{"text_chunk": "I'm a tool author, and want to dynamically list Azure resources in my tool input. What should I pay attention to?\n1. Clarify azure workspace triple \"subscription_id\", \"resource_group_name\", \"workspace_name\" in the list function signature. System helps append workspace triple to function input parameters if they are in function signature. See list_endpoint_names as an example.\n```python\ndef list_endpoint_names(subscription_id, resource_group_name, workspace_name, prefix: str = \"\") -> List[Dict[str, str]]:\n \"\"\"This is an example to show how to get Azure ML resource in tool input list function.\n\n :param subscription_id: Azure subscription id.\n :param resource_group_name: Azure resource group name.\n :param workspace_name: Azure ML workspace name.\n :param prefix: prefix to add to each item.\n \"\"\"\n from azure.ai.ml import MLClient\n from azure.identity import DefaultAzureCredential\n\n credential = DefaultAzureCredential()\n credential.get_token(\"https://management.azure.com/.default\")\n\n ml_client = MLClient(\n credential=credential,\n subscription_id=subscription_id,\n resource_group_name=resource_group_name,\n workspace_name=workspace_name)\n result = []\n for ep in ml_client.online_endpoints.list():\n hyperlink = (\n f\"https://ml.azure.com/endpoints/realtime/{ep.name}/detail?wsid=/subscriptions/\"\n f\"{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.\"\n f\"MachineLearningServices/workspaces/{workspace_name}\"\n )\n cur_item = {\n \"value\": ep.name,\n \"display_value\": f\"{prefix}_{ep.name}\",\n # external link to jump to the endpoint page.\n \"hyperlink\": hyperlink,\n \"description\": f\"this is endpoint: {ep.name}\",\n }\n result.append(cur_item)\n return result\n```\n2. Note in your tool doc that if your tool user want to use the tool at local, they should login to azure and set ws triple as default. Or the tool input will be empty and user can't select anything.\n```sh\naz login\naz account set --subscription \naz configure --defaults group= workspace=\n```\nInstall azure dependencies.\n```sh\npip install azure-ai-ml\n```\n```sh\npip install my-tools-package[azure]>=0.0.8\n```\n!dynamic list function azure"} +{"text_chunk": "I'm a tool user, and cannot see any options in dynamic list tool input. What should I do?\n\nIf you are unable to see any options in a dynamic list tool input, you may see an error message below the input field stating:\n\n\"Unable to display list of items due to XXX. Please contact the tool author/support team for troubleshooting assistance.\"\n\nIf this occurs, follow these troubleshooting steps:\n\n- Note the exact error message shown. This provides details on why the dynamic list failed to populate.\n- Contact the tool author/support team and report the issue. Provide the error message so they can investigate the root cause."} +{"text_chunk": "Create and use your own custom strong type connection\nConnections provide a secure method for managing credentials for external APIs and data sources in prompt flow. This guide explains how to create and use a custom strong type connection."} +{"text_chunk": "What is a Custom Strong Type Connection?\nA custom strong type connection in prompt flow allows you to define a custom connection class with strongly typed keys. This provides the following benefits:\n\n* Enhanced user experience - no need to manually enter connection keys.\n* Rich intellisense experience - defining key types enables real-time suggestions and auto-completion of available keys as you work in VS Code.\n* Central location to view available keys and data types.\n\nFor other connections types, please refer to Connections."} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to at least version 1.2.1.\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```"} +{"text_chunk": "Create a custom strong type connection\nFollow these steps to create a custom strong type connection:\n\n1. Define a Python class inheriting from `CustomStrongTypeConnection`.\n > [!Note] Please avoid using the `CustomStrongTypeConnection` class directly.\n\n2. Use the Secret type to indicate secure keys. This enhances security by scrubbing secret keys.\n\n3. Document with docstrings explaining each key.\n\nFor example:\n\n```python\nfrom promptflow.connections import CustomStrongTypeConnection\nfrom promptflow.contracts.types import Secret\n\n\nclass MyCustomConnection(CustomStrongTypeConnection):\n \"\"\"My custom strong type connection.\n\n :param api_key: The api key.\n :type api_key: Secret\n :param api_base: The api base.\n :type api_base: String\n \"\"\"\n api_key: Secret\n api_base: str = \"This is a fake api base.\"\n\n```\n\nSee this example for a complete implementation."} +{"text_chunk": "Use the connection in a flow\nOnce you create a custom strong type connection, here are two ways to use it in your flows:"} +{"text_chunk": "With Package Tools:\n\n1. Refer to the Create and Use Tool Package to build and install your tool package containing the connection.\n\n2. Develop a flow with custom tools. Please take this folder as an example.\n\n3. Create a custom strong type connection using one of the following methods:\n - If the connection type hasn't been created previously, click the 'Add connection' button to create the connection.\n !create_custom_strong_type_connection_in_node_interface\n - Click the 'Create connection' plus sign in the CONNECTIONS section.\n !create_custom_strong_type_connection_add_sign\n - Click 'Create connection' plus sign in the Custom category.\n !create_custom_strong_type_connection_in_custom_category \n\n4. Fill in the `values` starting with `to-replace-with` in the connection template.\n!custom_strong_type_connection_template\n\n5. Run the flow with the created custom strong type connection.\n!use_custom_strong_type_connection_in_flow"} +{"text_chunk": "With Script Tools:\n\n1. Develop a flow with python script tools. Please take this folder as an example.\n\n2. Create a `CustomConnection`. Fill in the `keys` and `values` in the connection template.\n !custom\n\n3. Run the flow with the created custom connection.\n !use_custom_connection_in_flow"} +{"text_chunk": "Local to cloud\nWhen creating the necessary connections in Azure AI, you will need to create a `CustomConnection`. In the node interface of your flow, this connection will be displayed as the `CustomConnection` type.\n\nPlease refer to Run prompt flow in Azure AI for more details.\n\nHere is an example command:\n```\npfazure run create --subscription 96aede12-2f73-41cb-b983-6d11a904839b -g promptflow -w my-pf-eus --flow D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection --data D:\\proj\\github\\ms\\promptflow\\examples\\flows\\standard\\flow-with-package-tool-using-custom-strong-type-connection\\data.jsonl --runtime test-compute\n```"} +{"text_chunk": "FAQs"} +{"text_chunk": "I followed the steps to create a custom strong type connection, but it's not showing up. What could be the issue?\n\nOnce the new tool package is installed in your local environment, a window reload is necessary. This action ensures that the new tools and custom strong type connections become visible and accessible."} +{"text_chunk": "Customizing an LLM tool\nIn this document, we will guide you through the process of customizing an LLM tool, allowing users to seamlessly connect to a large language model with prompt tuning experience using a `PromptTemplate`."} +{"text_chunk": "Prerequisites\n- Please ensure that your Prompt flow for VS Code is updated to version 1.2.0 or later."} +{"text_chunk": "How to customize an LLM tool\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package. \n\nDevelop the tool code as in this example.\n- Add a `CustomConnection` input to the tool, which is used to authenticate and establish a connection to the large language model.\n- Add a `PromptTemplate` input to the tool, which serves as an argument to be passed into the large language model.\n\n ```python\n from jinja2 import Template\n from promptflow import tool\n from promptflow.connections import CustomConnection\n from promptflow.contracts.types import PromptTemplate\n\n\n @tool\n def my_tool(connection: CustomConnection, prompt: PromptTemplate, **kwargs) -> str:\n # Customize your own code to use the connection and prompt here.\n rendered_prompt = Template(prompt, trim_blocks=True, keep_trailing_newline=True).render(**kwargs)\n return rendered_prompt\n ```"} +{"text_chunk": "Use the tool in VS Code\nFollow the steps to build and install your tool package and use your tool from VS Code extension. \n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension. \n- There is a node named \"my_custom_llm_tool\" with a prompt template file. You can either use an existing file or create a new one as the prompt template file. \n!use_my_custom_llm_tool"} +{"text_chunk": "Using file path as tool input\n\nUsers sometimes need to reference local files within a tool to implement specific logic. To simplify this, we've introduced the `FilePath` input type. This input type enables users to either select an existing file or create a new one, then pass it to a tool, allowing the tool to access the file's content.\n\nIn this guide, we will provide a detailed walkthrough on how to use `FilePath` as a tool input. We will also demonstrate the user experience when utilizing this type of tool within a flow."} +{"text_chunk": "Prerequisites\n\n- Please install promptflow package and ensure that its version is 1.0.0 or later.\n ```\n pip install promptflow>=1.0.0\n ```\n- Please ensure that your Prompt flow for VS Code is updated to version 1.1.0 or later."} +{"text_chunk": "Using File Path as Package Tool Input"} +{"text_chunk": "How to create a package tool with file path input\n\nHere we use an existing tool package as an example. If you want to create your own tool, please refer to create and use tool package.\n\nAdd a `FilePath` input for your tool, like in this example.\n\n```python\nimport importlib\nfrom pathlib import Path\nfrom promptflow import tool"} +{"text_chunk": "1. import the FilePath type\nfrom promptflow.contracts.types import FilePath"} +{"text_chunk": "2. add a FilePath input for your tool method\n@tool()\ndef my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n\n return new_module.hello(input_text) \n```\n\n> !Note] tool yaml file can be generated using a python script. For further details, please refer to [create custom tool package."} +{"text_chunk": "Use tool with a file path input in VS Code extension\n\nFollow steps to build and install your tool package and use your tool from VS Code extension.\n\nHere we use an existing flow to demonstrate the experience, open this flow in VS Code extension:\n\n- There is a node named \"Tool_with_FilePath_Input\" with a `file_path` type input called `input_file`.\n- Click the picker icon to open the UI for selecting an existing file or creating a new file to use as input.\n\n !use file path in flow"} +{"text_chunk": "Using File Path as Script Tool Input\n\nWe can also utilize the `FilePath` input type directly in a script tool, eliminating the need to create a package tool.\n\n1. Initiate an empty flow in the VS Code extension and add a python node titled 'python_node_with_filepath' into it in the Visual Editor page.\n2. Select the link `python_node_with_filepath.py` in the node to modify the python method to include a `FilePath` input as shown below, and save the code change.\n ```python\n import importlib\n from pathlib import Path\n from promptflow import tool\n # 1. import the FilePath type\n from promptflow.contracts.types import FilePath\n\n # 2. add a FilePath input for your tool method\n @tool\n def my_tool(input_file: FilePath, input_text: str) -> str:\n # 3. customise your own code to handle and use the input_file here\n new_module = importlib.import_module(Path(input_file).stem)\n \n return new_module.hello(input_text) \n ```\n\n3. Return to the flow Visual Editor page, click the picker icon to launch the UI for selecting an existing file or creating a new file to use as input, here we select this file as an example.\n \n !use file path in script tool"} +{"text_chunk": "FAQ"} +{"text_chunk": "What are some practical use cases for this feature?\nThe `FilePath` input enables several useful workflows:\n\n1. **Dynamically load modules** - As shown in the demo, you can load a Python module from a specific script file selected by the user. This allows flexible custom logic.\n2. **Load arbitrary data files** - The tool can load data from files like .csv, .txt, .json, etc. This provides an easy way to inject external data into a tool.\n\nSo in summary, `FilePath` input gives tools flexible access to external files provided by users at runtime. This unlocks many useful scenarios like the ones above."} +{"text_chunk": "Use streaming endpoints deployed from prompt flow\n\nIn prompt flow, you can deploy flow as REST endpoint for real-time inference.\n\nWhen consuming the endpoint by sending a request, the default behavior is that the online endpoint will keep waiting until the whole response is ready, and then send it back to the client. This can cause a long delay for the client and a poor user experience.\n\nTo avoid this, you can use streaming when you consume the endpoints. Once streaming enabled, you don't have to wait for the whole response ready. Instead, the server will send back the response in chunks as they are generated. The client can then display the response progressively, with less waiting time and more interactivity.\n\nThis article will describe the scope of streaming, how streaming works, and how to consume streaming endpoints."} +{"text_chunk": "Create a streaming enabled flow\n\nIf you want to use the streaming mode, you need to create a flow that has a node that produces a string generator as the flow\u2019s output. A string generator is an object that can return one string at a time when requested. You can use the following types of nodes to create a string generator:\n\n- LLM node: This node uses a large language model to generate natural language responses based on the input.\n ```jinja\n {# Sample prompt template for LLM node #}\n\n system:\n You are a helpful assistant.\n\n user:\n {{question}}\n ```\n- Python tools node: This node allows you to write custom Python code that can yield string outputs. You can use this node to call external APIs or libraries that support streaming. For example, you can use this code to echo the input word by word:\n ```python\n from promptflow import tool\n\n # Sample code echo input by yield in Python tool node\n\n @tool\n def my_python_tool(paragraph: str) -> str:\n yield \"Echo: \"\n for word in paragraph.split():\n yield word + \" \"\n ```\n\nIn this guide, we will use the \"Chat with Wikipedia\" sample flow as an example. This flow processes the user\u2019s question, searches Wikipedia for relevant articles, and answers the question with information from the articles. It uses streaming mode to show the progress of the answer generation.\n\n!chat_wikipedia.png"} +{"text_chunk": "Deploy the flow as an online endpoint\n\nTo use the streaming mode, you need to deploy your flow as an online endpoint. This will allow you to send requests and receive responses from your flow in real time.\n\nFollow this guide to deploy your flow as an online endpoint.\n\n> [!NOTE]\n> \n> You can follow this document to deploy an online endpoint.\n> Please deploy with runtime environment version later than version `20230816.v10`.\n> You can check your runtime version and update runtime in the run time detail page."} +{"text_chunk": "Understand the streaming process\n\nWhen you have an online endpoint, the client and the server need to follow specific principles for content negotiation to utilize the streaming mode:\n\nContent negotiation is like a conversation between the client and the server about the preferred format of the data they want to send and receive. It ensures effective communication and agreement on the format of the exchanged data.\n\nTo understand the streaming process, consider the following steps:\n\n- First, the client constructs an HTTP request with the desired media type included in the `Accept` header. The media type tells the server what kind of data format the client expects. It's like the client saying, \"Hey, I'm looking for a specific format for the data you'll send me. It could be JSON, text, or something else.\" For example, `application/json` indicates a preference for JSON data, `text/event-stream` indicates a desire for streaming data, and `*/*` means the client accepts any data format.\n > [!NOTE]\n > \n > If a request lacks an `Accept` header or has empty `Accept` header, it implies that the client will accept any media type in response. The server treats it as `*/*`.\n \n- Next, the server responds based on the media type specified in the `Accept` header. It's important to note that the client may request multiple media types in the `Accept` header, and the server must consider its capabilities and format priorities to determine the appropriate response.\n - First, the server checks if `text/event-stream` is explicitly specified in the `Accept` header:\n - For a stream-enabled flow, the server returns a response with a `Content-Type` of `text/event-stream`, indicating that the data is being streamed.\n - For a non-stream-enabled flow, the server proceeds to check for other media types specified in the header.\n - If `text/event-stream` is not specified, the server then checks if `application/json` or `*/*` is specified in the `Accept` header:\n - In such cases, the server returns a response with a `Content-Type` of `application/json`, providing the data in JSON format.\n - If the `Accept` header specifies other media types, such as `text/html`:\n - The server returns a `424` response with a PromptFlow runtime error code `UserError` and a runtime HTTP status `406`, indicating that the server cannot fulfill the request with the requested data format.\n > Note: Please refer handle errors for details.\n- Finally, the client checks the `Content-Type` response header. If it is set to `text/event-stream`, it indicates that the data is being streamed.\n\nLet\u2019s take a closer look at how the streaming process works. The response data in streaming mode follows the format of server-sent events (SSE).\n\nThe overall process works as follows:"} +{"text_chunk": "0. The client sends a message to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Hello\",\n \"chat_history\": []\n}\n```\n> [!NOTE]\n> \n> The `Accept` header is set to `text/event-stream` to request a stream response."} +{"text_chunk": "1. The server sends back the response in streaming mode.\n\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Hello\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" How\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" assist\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" today\"}\n\ndata: {\"answer\": \" ?\"}\n\ndata: {\"answer\": \"\"}\n\n```\n\nNote that the `Content-Type` is set to `text/event-stream; charset=utf-8`, indicating the response is an event stream.\n\nThe client should decode the response data as server-sent events and display them incrementally. The server will close the HTTP connection after all the data is sent.\n\nEach response event is the delta to the previous event. It is recommended for the client to keep track of the merged data in memory and send them back to the server as chat history in the next request."} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n\n{\n \"question\": \"Glad to know you!\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"Hello\"\n },\n \"outputs\": {\n \"answer\": \"Hello! How can I assist you today?\"\n }\n }\n ]\n}\n```"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Nice\"}\n\ndata: {\"answer\": \" to\"}\n\ndata: {\"answer\": \" know\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" too\"}\n\ndata: {\"answer\": \"!\"}\n\ndata: {\"answer\": \" Is\"}\n\ndata: {\"answer\": \" there\"}\n\ndata: {\"answer\": \" anything\"}\n\ndata: {\"answer\": \" I\"}\n\ndata: {\"answer\": \" can\"}\n\ndata: {\"answer\": \" help\"}\n\ndata: {\"answer\": \" you\"}\n\ndata: {\"answer\": \" with\"}\n\ndata: {\"answer\": \"?\"}\n\ndata: {\"answer\": \"\"}\n\n```"} +{"text_chunk": "4. The chat continues in a similar way."} +{"text_chunk": "Handle errors\n\nThe client should check the HTTP response code first. See this table for common error codes returned by online endpoints.\n\nIf the response code is \"424 Model Error\", it means that the error is caused by the model\u2019s code. The error response from a PromptFlow model always follows this format:\n\n```json\n{\n \"error\": {\n \"code\": \"UserError\",\n \"message\": \"Media type text/event-stream in Accept header is not acceptable. Supported media type(s) - application/json\",\n }\n}\n```\n* It is always a JSON dictionary with only one key \"error\" defined.\n* The value for \"error\" is a dictionary, containing \"code\", \"message\".\n* \"code\" defines the error category. Currently, it may be \"UserError\" for bad user inputs and \"SystemError\" for errors inside the service.\n* \"message\" is a description of the error. It can be displayed to the end user."} +{"text_chunk": "How to consume the server-sent events"} +{"text_chunk": "Consume using Python\n\nIn this sample usage, we are using the `SSEClient` class. This class is not a built-in Python class and needs to be installed separately. You can install it via pip:\n\n```bash\npip install sseclient-py \n```\n\nA sample usage would like:\n\n```python\nimport requests \nfrom sseclient import SSEClient \nfrom requests.exceptions import HTTPError \n\ntry:\n response = requests.post(url, json=body, headers=headers, stream=stream)\n response.raise_for_status()\n\n content_type = response.headers.get('Content-Type')\n if \"text/event-stream\" in content_type:\n client = SSEClient(response)\n for event in client.events():\n # Handle event, i.e. print to stdout\n else:\n # Handle json response\n\nexcept HTTPError:\n # Handle exceptions\n```"} +{"text_chunk": "Consume using JavaScript\n\nThere are several libraries to consume server-sent events in JavaScript. Here is one of them as an example."} +{"text_chunk": "A sample chat app using Python\n\nHere is a sample chat app written in Python.\n(Click here to view the source code.)\n\n!chat_app"} +{"text_chunk": "Advance usage - hybrid stream and non-stream flow output\nSometimes, you may want to get both stream and non-stream results from a flow output. For example, in the \u201cChat with Wikipedia\u201d flow, you may want to get not only LLM\u2019s answer, but also the list of URLs that the flow searched. To do this, you need to modify the flow to output a combination of stream LLM\u2019s answer and non-stream URL list.\n\nIn the sample \"Chat With Wikipedia\" flow, the output is connected to the LLM node `augmented_chat`. To add the URL list to the output, you need to add an output field with the name `url` and the value `${get_wiki_url.output}`.\n\n!chat_wikipedia_dual_output_center.png\n\nThe output of the flow will be a non-stream field as the base and a stream field as the delta. Here is an example of request and response."} +{"text_chunk": "0. The client sends a message to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When was ChatGPT launched?\",\n \"chat_history\": []\n}\n```"} +{"text_chunk": "1. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=ChatGPT\", \"https://en.wikipedia.org/w/index.php?search=GPT-4\"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" \\n\\n\"}\n\n...\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```"} +{"text_chunk": "2. The client sends another chat message, along with the full chat history, to the server.\n```\nPOST https://.inference.ml.azure.com/score\nContent-Type: application/json\nAuthorization: Bearer \nAccept: text/event-stream\n{\n \"question\": \"When did OpenAI announce GPT-4? How long is it between these two milestones?\",\n \"chat_history\": [\n {\n \"inputs\": {\n \"question\": \"When was ChatGPT launched?\"\n },\n \"outputs\": {\n \"url\": [\n \"https://en.wikipedia.org/w/index.php?search=ChatGPT\",\n \"https://en.wikipedia.org/w/index.php?search=GPT-4\"\n ],\n \"answer\": \"ChatGPT was launched on November 30, 2022. \\n\\nSOURCES: https://en.wikipedia.org/w/index.php?search=ChatGPT\"\n }\n }\n ]\n}\n```"} +{"text_chunk": "3. The server sends back the answer in streaming mode.\n```\nHTTP/1.1 200 OK\nContent-Type: text/event-stream; charset=utf-8\nConnection: close\nTransfer-Encoding: chunked\n\ndata: {\"url\": [\"https://en.wikipedia.org/w/index.php?search=Generative pre-trained transformer \", \"https://en.wikipedia.org/w/index.php?search=Microsoft \"]}\n\ndata: {\"answer\": \"\"}\n\ndata: {\"answer\": \"Open\"}\n\ndata: {\"answer\": \"AI\"}\n\ndata: {\"answer\": \" released\"}\n\ndata: {\"answer\": \" G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"-\"}\n\ndata: {\"answer\": \"4\"}\n\ndata: {\"answer\": \" in\"}\n\ndata: {\"answer\": \" March\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \" was\"}\n\ndata: {\"answer\": \" launched\"}\n\ndata: {\"answer\": \" on\"}\n\ndata: {\"answer\": \" November\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"30\"}\n\ndata: {\"answer\": \",\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"202\"}\n\ndata: {\"answer\": \"2\"}\n\ndata: {\"answer\": \".\"}\n\ndata: {\"answer\": \" The\"}\n\ndata: {\"answer\": \" time\"}\n\ndata: {\"answer\": \" between\"}\n\ndata: {\"answer\": \" these\"}\n\ndata: {\"answer\": \" two\"}\n\ndata: {\"answer\": \" milestones\"}\n\ndata: {\"answer\": \" is\"}\n\ndata: {\"answer\": \" approximately\"}\n\ndata: {\"answer\": \" \"}\n\ndata: {\"answer\": \"3\"}\n\ndata: {\"answer\": \" months\"}\n\ndata: {\"answer\": \".\\n\\n\"}\n\n...\n\ndata: {\"answer\": \"Chat\"}\n\ndata: {\"answer\": \"G\"}\n\ndata: {\"answer\": \"PT\"}\n\ndata: {\"answer\": \"\"}\n```"} +{"text_chunk": "Execute flow as a function\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::"} +{"text_chunk": "Overview\n\nPromptflow allows you to load a flow and use it as a function in your code.\nThis feature is useful when building a service on top of a flow, reference here for a simple example service with flow function consumption."} +{"text_chunk": "Load an invoke the flow function\n\nTo use the flow-as-function feature, you first need to load a flow using the `load_flow` function.\nThen you can consume the flow object like a function by providing key-value arguments for it.\n\n```python\nf = load_flow(\"../../examples/flows/standard/web-classification/\")\nf(url=\"sample_url\")\n```"} +{"text_chunk": "Config the flow with context\n\nYou can overwrite some flow configs before flow function execution by setting `flow.context`."} +{"text_chunk": "Load flow as a function with in-memory connection override\n\nBy providing a connection object to flow context, flow won't need to get connection in execution time, which can save time when for cases where flow function need to be called multiple times.\n\n```python\nfrom promptflow.entities import AzureOpenAIConnection\n\nconnection_obj = AzureOpenAIConnection(\n name=conn_name,\n api_key=api_key,\n api_base=api_base,\n api_type=\"azure\",\n api_version=api_version,\n)"} +{"text_chunk": "no need to create the connection object.\nf.context = FlowContext(\n connections={\"classify_with_llm\": {\"connection\": connection_obj}}\n)\n```"} +{"text_chunk": "Local flow as a function with flow inputs override\n\nBy providing overrides, the original flow dag will be updated in execution time.\n\n```python\nf.context = FlowContext(\n # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n)\n```\n\n**Note**, the `overrides` are only doing YAML content replacement on original `flow.dag.yaml`.\nIf the `flow.dag.yaml` become invalid after `overrides`, validation error will be raised when executing."} +{"text_chunk": "Load flow as a function with streaming output\n\nAfter set `streaming` in flow context, the flow function will return an iterator to stream the output.\n\n```python\nf = load_flow(source=\"../../examples/flows/chat/basic-chat/\")\nf.context.streaming = True\nresult = f(\n chat_history=[\n {\n \"inputs\": {\"chat_input\": \"Hi\"},\n \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n }\n ],\n question=\"How are you?\",\n)\n\n\nanswer = \"\""} +{"text_chunk": "the result will be a generator, iterate it to get the result\nfor r in result[\"answer\"]:\n answer += r\n\n```\n\nReference our sample for usage."} +{"text_chunk": "Next steps\n\nLearn more about:\n\n- Flow as a function sample\n- Deploy a flow"} +{"text_chunk": "Frequency asked questions (FAQ)"} +{"text_chunk": "General"} +{"text_chunk": "Stable vs experimental\n\nPrompt flow provides both stable and experimental features in the same SDK.\n\n|Feature status | Description | \n|----------------|----------------|\nStable features\t| **Production ready** These features are recommended for most use cases and production environments. They are updated less frequently then experimental features.|\nExperimental features | **Developmental** These features are newly developed capabilities & updates that may not be ready or fully tested for production usage. While the features are typically functional, they can include some breaking changes. Experimental features are used to iron out SDK breaking bugs, and will only receive updates for the duration of the testing period. Experimental features are also referred to as features that are in **preview**. As the name indicates, the experimental (preview) features are for experimenting and is **not considered bug free or stable**. For this reason, we only recommend experimental features to advanced users who wish to try out early versions of capabilities and updates, and intend to participate in the reporting of bugs and glitches."} +{"text_chunk": "OpenAI 1.x support\nPlease use the following command to upgrade promptflow for openai 1.x support:\n```\npip install promptflow>=1.1.0\npip install promptflow-tools>=1.0.0\n```\nNote that the command above will upgrade your openai package a version later than 1.0.0, \nwhich may introduce breaking changes to custom tool code.\n\nReach OpenAI migration guide for more details."} +{"text_chunk": "Troubleshooting"} +{"text_chunk": "Connection creation failed with StoreConnectionEncryptionKeyError\n\n```\nConnection creation failed with StoreConnectionEncryptionKeyError: System keyring backend service not found in your operating system. See https://pypi.org/project/keyring/ to install requirement for different operating system, or 'pip install keyrings.alt' to use the third-party backend.\n```\n\nThis error raised due to keyring can't find an available backend to store keys.\nFor example macOS Keychain and Windows Credential Locker\nare valid keyring backends.\n\nTo resolve this issue, install the third-party keyring backend or write your own keyring backend, for example:\n`pip install keyrings.alt`\n\nFor more detail about keyring third-party backend, please refer to 'Third-Party Backends' in keyring."} +{"text_chunk": "Pf visualize show error: \"tcgetpgrp failed: Not a tty\"\n\nIf you are using WSL, this is a known issue for `webbrowser` under WSL; see this issue for more information. Please try to upgrade your WSL to 22.04 or later, this issue should be resolved.\n\nIf you are still facing this issue with WSL 22.04 or later, or you are not even using WSL, please open an issue to us."} +{"text_chunk": "Installed tool not appearing in VSCode Extension tool list\n\nAfter installing a tool package via `pip install [tool-package-name]`, the new tool may not immediately appear in the tool list within the VSCode Extension, as shown below:\n\n!VSCode Extension tool list\n\nThis is often due to outdated cache. To refresh the tool list and make newly installed tools visible:\n\n1. Open the VSCode Extension window.\n\n2. Bring up the command palette by pressing \"Ctrl+Shift+P\".\n\n3. Type and select the \"Developer: Reload Webviews\" command. \n\n4. Wait a moment for the tool list refreshing.\n\nReloading clears the previous cache and populates the tool list with any newly installed tools. So that the missing tools are now visible."} +{"text_chunk": "Set logging level\n\nPromptflow uses `logging` module to log messages. You can set logging level via environment variable `PF_LOGGING_LEVEL`, valid values includes `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`, default to `INFO`.\nBelow is the serving logs after setting `PF_LOGGING_LEVEL` to `DEBUG`:\n\n!img\n\nCompare to the serving logs with `WARNING` level:\n\n!img"} +{"text_chunk": "Set environment variables\n\nCurrently, promptflow supports the following environment variables:\n\n**PF_WORKER_COUNT** \n\nValid for batch run only. The number of workers to use for parallel execution of the Flow.\n\nDefault value is 16. If you have large number of batch run date row count, and want more efficiency, you can increase the PF_WORKER_COUNT to improve the batch run concurrency, make it run faster.\n\nWhen you modify the concurrency, please consider 2 points:\n\nFirst, the concurrency should be not bigger than your batch run data row count. If not, meaning if the concurrency is bigger, it will run slower due to the time taken for process startup and shutdown.\n\nSecond, your batch run risks to fail due to rate limit of your LLM endpoint, in this case you need to set up PF_WORKER_COUNT to a smaller number. Take Azure OpenAI endpoint as example, you can go to Azure OpenAI Studio, navigate to Deployment tab, check out the capacity of your endpoints. Then you can refer to this expression to set up the concurrency.\n\n```\nPF_WORKER_COUNT <= TPM * duration_seconds / token_count / 60\n```\nTPM: token per minute, capacity rate limit of your LLM endpoint\n\nduration_seconds: single flow run duration in seconds\n\ntoken_count: single flow run token count\n\n\nFor example, if your endpoint TPM (token per minute) is 50K, the single flow run takes 10k tokens and runs for 30s, pls do not set up PF_WORKER_COUNT bigger than 2. This is a rough estimation. Please also consider collboaration (teammates use the same endpoint at the same time) and tokens consumed in deployed inference endpoints, playground and other cases which might send request to your LLM endpoints.\n\n**PF_BATCH_METHOD**\n\nValid for batch run only. Optional values: 'spawn', 'fork'. \n\n**spawn**\n\n1. The child processes will not inherit resources of the parent process, therefore, each process needs to reinitialize the resources required for the flow, which may use more system memory.\n\n2. Starting a process is slow because it will take some time to initialize the necessary resources.\n \n**fork**\n\n1. Use the copy-on-write mechanism, the child processes will inherit all the resources of the parent process, thereby using less system memory.\n\n2. The process starts faster as it doesn't need to reinitialize resources.\n \nNote: Windows only supports spawn, Linux and macOS support both spawn and fork."} +{"text_chunk": "You can configure environment variables in the following ways\n\n1. If you are using CLI, you can use this parameter: ```--environment-variable```. Example: ```--environment-variable PF_WORKER_COUNT=\"2\" PF_BATCH_METHOD=\"spawn\"```.\n\n2. If you are using SDK, you can specify environment variables when creating run. Example: \n\n``` python\n pf = PFClient(\n credential=credential,\n subscription_id=\"\",\n resource_group_name=\"\",\n workspace_name=\"\",\n )\n\n flow = \"web-classification\"\n data = \"web-classification/data.jsonl\"\n runtime = \"example-runtime-ci\"\n\n environment_variables = {\"PF_WORKER_COUNT\": \"2\", \"PF_BATCH_METHOD\": \"spawn\"}\n\n # create run\n base_run = pf.run(\n flow=flow,\n data=data,\n runtime=runtime,\n environment_variables=environment_variables,\n )\n```\n\n3. If you are using VSCode Extension to submit batch run, you can configure environment variables in the ```batch_run_create.yaml```. Example:\n\n``` yaml\n name: flow_name\n display_name: display_name\n flow: flow_folder\n data: data_file\n column_mapping:\n customer_info: \n history: \n environment_variables:\n PF_WORKER_COUNT: \"2\"\n PF_BATCH_METHOD: \"spawn\"\n```"} +{"text_chunk": "Initialize and test a flow\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nFrom this document, customer can initialize a flow and test it."} +{"text_chunk": "Initialize flow\n\nCreating a flow folder with code/prompts and yaml definitions of the flow."} +{"text_chunk": "Initialize flow from scratch\n\nPromptflow can create three types of flow folder:\n- standard: Basic structure of flow folder.\n- chat: Chat flow is designed for conversational application development, building upon the capabilities of standard flow and providing enhanced support for chat inputs/outputs and chat history management.\n- evaluation: Evaluation flows are special types of flows that assess how well the outputs of a flow align with specific criteria and goals.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash"} +{"text_chunk": "Create a flow\npf flow init --flow"} +{"text_chunk": "Create a chat flow\npf flow init --flow --type chat\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse VS Code explorer pane > directory icon > right click > the \"New flow in this directory\" action. Follow the popped out dialog to initialize your flow in the target folder.\n!img\n\nAlternatively, you can use the \"Create new flow\" action on the prompt flow pane > quick access section to create a new flow\n!img\n\n:::\n\n::::\n\n\nStructure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n!init_flow_folder"} +{"text_chunk": "Create from existing code\n\nCustomer needs to pass the path of tool script to `entry`, and also needs to pass in the promptflow template dict to `prompt-template`, which the key is the input name of the tool and the value is the path to the promptflow template.\nPromptflow CLI can generate the yaml definitions needed for prompt flow from the existing folder, using the tools script and prompt templates.\n\n```bash"} +{"text_chunk": "Create a flow in existing folder\npf flow init --flow --entry --function --prompt-template =\n```\n\nTake customer-intent-extraction for example, which demonstrating how to convert a langchain code into a prompt flow.\n\n!init_output\n\nIn this case, promptflow CLI generates `flow.dag.yaml`, `.promptflow/flow.tools.json` and `extract_intent_tool.py`, it is a python tool in the flow.\n\n!init_files"} +{"text_chunk": "Test a flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\nPromptflow also provides ways to test the initialized flow or flow node. It will help you quickly test your flow."} +{"text_chunk": "Visual editor on the VS Code for prompt flow.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nOpen the flow.dag.yaml file of your flow. On the top of the yaml editor you can find the \"Visual editor\" action. Use it to open the Visual editor with GUI support.\n\n!img\n:::\n\n::::"} +{"text_chunk": "Test flow\n\nCustomer can use CLI or VS Code extension to test the flow.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\n```bash"} +{"text_chunk": "Test flow\npf flow test --flow"} +{"text_chunk": "Test flow with specified variant\npf flow test --flow --variant '${.}'\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nprint(f\"Flow outputs: {flow_result}\")\n```\n\nThe log and result of flow test will be displayed in the terminal.\n\n!flow test\n\nPromptflow CLI will generate test logs and outputs in `.promptflow`:\n- **flow.detail.json**: Defails info of flow test, include the result of each node.\n- **flow.log**: The log of flow test.\n- **flow.output.json**: The result of flow test.\n\n!flow_output_files\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can use the action either on the default yaml editor or the visual editor to trigger flow test. See the snapshots below:\n!img\n!img\n\n:::\n\n::::"} +{"text_chunk": "Test a single node in the flow\n\nCustomer can test a single python node in the flow. It will use customer provides date or the default value of the node as input. It will only use customer specified node to execute with the input.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nCustomer can execute this command to test the flow.\n\n```bash"} +{"text_chunk": "Test flow node\npf flow test --flow --node \n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nCustomer can execute this command to test the flow. The return value of `test` function is the node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} +{"text_chunk": "Test not iun the flow\ninputs = {: } # The inputs of the node.\nnode_result = pf_client.test(flow=, inputs=inputs, node=)\nprint(f\"Node outputs: {node_result}\")\n```\n\nThe log and result of flow node test will be displayed in the terminal. And the details of node test will generated to `.promptflow/flow-.node.detail.json`.\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nThe prompt flow extension provides inline actions in both default yaml editor and visual editor to trigger single node runs.\n\n!img\n!img\n\n:::\n\n::::"} +{"text_chunk": "Test with interactive mode\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nPromptflow CLI provides a way to start an interactive chat session for chat flow. Customer can use below command to start an interactive chat session:\n\n```bash"} +{"text_chunk": "Chat in the flow\npf flow test --flow --interactive\n```\n\nAfter executing this command, customer can interact with the chat flow in the terminal. Customer can press **Enter** to send the message to chat flow. And customer can quit with **ctrl+C**.\nPromptflow CLI will distinguish the output of different roles by color, User input, Bot output, Flow script output, Node output.\n\nUsing this chat flow to show how to use interactive mode.\n\n!chat\n\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nIf a flow contains chat inputs or chat outputs in the flow interface, there will be a selection when triggering flow test. You can select the interactive mode if you want to.\n\n!img\n!img\n\n:::\n\n::::\n\nWhen the LLM node in the chat flow that is connected to the flow output, Promptflow SDK streams the results of the LLM node.\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe flow result will be streamed in the terminal as shown below.\n\n!streaming_output\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe LLM node return value of `test` function is a generator, you can consume the result by this way:\n\n```python\nfrom promptflow import PFClient\n\npf_client = PFClient()"} +{"text_chunk": "Test flow\ninputs = {\"\": \"\"} # The inputs of the flow.\nflow_result = pf_client.test(flow=\"\", inputs=inputs)\nfor item in flow_result[\"\"]:\n print(item)\n```\n\n:::\n\n::::"} +{"text_chunk": "Debug a single node in the flow\n\nCustomer can debug a single python node in VScode by the extension.\n\n::::{tab-set}\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nBreak points and debugging functionalities for the Python steps in your flow. Just set the break points and use the debug actions on either default yaml editor or visual editor.\n!img\n!img\n\n:::\n\n::::"} +{"text_chunk": "Next steps\n\n- Add conditional control to a flow"} +{"text_chunk": "Manage connections\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nConnection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM (Large Language Models) and other external tools, for example, Azure Content Safety.\n\n:::{note}\nTo use azureml workspace connection locally, refer to this guide.\n:::"} +{"text_chunk": "Connection types\nThere are multiple types of connections supported in promptflow, which can be simply categorized into **strong type connection** and **custom connection**. The strong type connection includes AzureOpenAIConnection, OpenAIConnection, etc. The custom connection is a generic connection type that can be used to store custom defined credentials.\n\nWe are going to use AzureOpenAIConnection as an example for strong type connection, and CustomConnection to show how to manage connections."} +{"text_chunk": "Create a connection\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nEach of the strong type connection has a corresponding yaml schema, the example below shows the AzureOpenAIConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: azure_open_ai_connection\ntype: azure_open_ai\napi_key: \"\"\napi_base: \"https://.openai.azure.com/\"\napi_type: \"azure\"\napi_version: \"2023-03-15-preview\"\n```\nThe custom connection yaml will have two dict fields for secrets and configs, the example below shows the CustomConnection yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/CustomConnection.schema.json\nname: custom_connection\ntype: custom\nconfigs:\n endpoint: \"\"\n other_config: \"other_value\"\nsecrets: # required\n my_key: \"\"\n```\nAfter preparing the yaml file, use the CLI command below to create them:\n```bash"} +{"text_chunk": "Override keys with --set to avoid yaml file changes\npf connection create -f --set api_key="} +{"text_chunk": "Create the custom connection\npf connection create -f --set configs.endpoint= secrets.my_key=\n```\nThe expected result is as follows if the connection created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, each connection type has a corresponding class to create a connection. The following code snippet shows how to import the required class and create the connection:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection, CustomConnection"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} +{"text_chunk": "Initialize an AzureOpenAIConnection object\nconnection = AzureOpenAIConnection(\n name=\"my_azure_open_ai_connection\", \n api_key=\"\", \n api_base=\"\"\n api_version=\"2023-03-15-preview\"\n)"} +{"text_chunk": "Create the connection, note that api_key will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)"} +{"text_chunk": "Initialize a custom connection object\nconnection = CustomConnection(\n name=\"my_custom_connection\", \n # Secrets is a required field for custom connection\n secrets={\"my_key\": \"\"},\n configs={\"endpoint\": \"\", \"other_config\": \"other_value\"}\n)"} +{"text_chunk": "Create the connection, note that all secret values will be scrubbed in the returned result\nresult = pf.connections.create_or_update(connection)\nprint(result)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Click the \"+\" icon on the top right of it and follow the popped out instructions to create your new connection.\n\n!img\n!img\n:::\n::::"} +{"text_chunk": "Update a connection\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nThe commands below show how to update existing connections with new values:\n```bash"} +{"text_chunk": "Update an azure open ai connection with a new api base\npf connection update -n my_azure_open_ai_connection --set api_base='new_value'"} +{"text_chunk": "Update a custom connection\npf connection update -n my_custom_connection --set configs.other_config='new_value'\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nThe code snippet below shows how to update existing connections with new values:\n```python"} +{"text_chunk": "Update an azure open ai connection with a new api base\nconnection = pf.connections.get(name=\"my_azure_open_ai_connection\")\nconnection.api_base = \"new_value\"\nconnection.api_key = \"\" # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)"} +{"text_chunk": "Update a custom connection\nconnection = pf.connections.get(name=\"my_custom_connection\")\nconnection.configs[\"other_config\"] = \"new_value\"\nconnection.secrets = {\"key1\": \"val1\"} # secrets are required when updating connection using sdk\nresult = pf.connections.create_or_update(connection)\nprint(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::"} +{"text_chunk": "List connections\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nList connection command will return the connections with json list format, note that all secrets and api keys will be scrubbed:\n```bash\npf connection list\n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList connection command will return the connections object list, note that all secrets and api keys will be scrubbed:\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} +{"text_chunk": "List and print connections\nconnection_list = pf.connections.list()\nfor connection in connection_list:\n print(connection)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} +{"text_chunk": "Delete a connection\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nDelete a connection with the following command:\n```bash\npf connection delete -n \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nDelete a connection with the following code snippet:\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage connections\npf = PFClient()"} +{"text_chunk": "Delete the connection with specific name\nclient.connections.delete(name=\"my_custom_connection\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > prompt flow pane. You can find the connections pane to manage your local connections. Right click the item of the connection list to update or delete your connections.\n!img\n:::\n::::"} +{"text_chunk": "Next steps\n- Reach more detail about connection concepts.\n- Try the connection samples.\n- Consume connections from Azure AI."} +{"text_chunk": "Manage runs\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThis documentation will walk you through how to manage your runs with CLI, SDK and VS Code Extension. \n\nIn general:\n- For `CLI`, you can run `pf/pfazure run --help` in terminal to see the help messages.\n- For `SDK`, you can refer to Promptflow Python Library Reference and check `PFClient.runs` for more run operations.\n\nLet's take a look at the following topics:\n\n- Manage runs\n - Create a run\n - Get a run\n - Show run details\n - Show run metrics\n - Visualize a run\n - List runs\n - Update a run\n - Archive a run\n - Restore a run"} +{"text_chunk": "Create a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\nTo create a run against bulk inputs, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../web_classification\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n url: \"${data.url}\"\nvariant: ${summarize_text_content.variant_0}\n```\n\nTo create a run against existing run, you can write the following YAML file.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: ../classification_accuracy_evaluation\ndata: ../webClassification1.jsonl\ncolumn_mapping:\n groundtruth: \"${data.answer}\"\n prediction: \"${run.outputs.category}\"\nrun: \n```\n\nReference here for detailed information for column mapping.\nYou can find additional information about flow yaml schema in Run YAML Schema.\n\nAfter preparing the yaml file, use the CLI command below to create them:\n\n```bash"} +{"text_chunk": "create the flow run\npf run create -f"} +{"text_chunk": "create the flow run and stream output\npf run create -f --stream\n```\n\nThe expected result is as follows if the run is created successfully.\n\n!img\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUsing SDK, create `Run` object and submit it with `PFClient`. The following code snippet shows how to import the required class and create the run:\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import Run"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Initialize an Run object\nrun = Run( \n flow=\"\",\n # run flow against local data or existing run, only one of data & run can be specified. \n data=\"\",\n run=\"\",\n column_mapping={\"url\": \"${data.url}\"},\n variant=\"${summarize_text_content.variant_0}\"\n)"} +{"text_chunk": "Create the run\nresult = pf.runs.create_or_update(run)\nprint(result)\n\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nYou can click on the actions on the top of the default yaml editor or the visual editor for the flow.dag.yaml files to trigger flow batch runs.\n\n!img\n!img\n:::\n::::"} +{"text_chunk": "Get a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet a run in CLI with JSON format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Get and print the run\nrun = pf.runs.get(name=\"\")\nprint(run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} +{"text_chunk": "Show run details\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run details with TABLE format.\n\n```bash\npf run show --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run details with `PFClient`\n```python\nfrom promptflow import PFClient\nfrom tabulate import tabulate"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Get and print the run-details\nrun_details = pf.runs.get_details(name=\"\")\nprint(tabulate(details.head(max_results), headers=\"keys\", tablefmt=\"grid\"))\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} +{"text_chunk": "Show run metrics\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run show-metrics --name \n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nShow run metrics with `PFClient`\n```python\nfrom promptflow import PFClient\nimport json"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Get and print the run-metrics\nrun_details = pf.runs.get_metrics(name=\"\")\nprint(json.dumps(metrics, indent=4))\n```\n:::\n\n::::"} +{"text_chunk": "Visualize a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nVisualize run in browser.\n\n```bash\npf run visualize --name \n```\n\nA browser will open and display run outputs.\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nVisualize run with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Visualize the run\nclient.runs.visualize(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Select one or more items and click the \"visualize\" button on the top-right to visualize the local runs.\n\n!img\n:::\n::::"} +{"text_chunk": "List runs\n\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nList runs with JSON format.\n\n```bash\npf run list\n```\n\n!img\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nList with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "list runs\nruns = pf.runs.list()\nprint(runs)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n\nOn the VS Code primary sidebar > the prompt flow pane, there is a run list. It will list all the runs on your machine. Hover on it to view more details.\n!img\n:::\n::::"} +{"text_chunk": "Update a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nGet run metrics with JSON format.\n\n```bash\npf run update --name --set display_name=new_display_name\n```\n\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nUpdate run with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "Get and print the run-metrics\nrun = pf.runs.update(name=\"\", display_name=\"new_display_name\")\nprint(run)\n```\n:::\n::::"} +{"text_chunk": "Archive a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nArchive the run so it won't show in run list results.\n\n```bash\npf run archive --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nArchive with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "archive a run\nclient.runs.archive(name=\"\")\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VSC\n!img\n:::\n::::"} +{"text_chunk": "Restore a run\n\n::::{tab-set}\n:::{tab-item} CLI\n:sync: CLI\n\nRestore an archived run so it can show in run list results.\n\n```bash\npf run restore --name \n```\n:::\n\n\n:::{tab-item} SDK\n:sync: SDK\nRestore with `PFClient`\n```python\nfrom promptflow import PFClient"} +{"text_chunk": "Get a pf client to manage runs\npf = PFClient()"} +{"text_chunk": "restore a run\nclient.runs.restore(name=\"\")\n```\n:::\n::::"} +{"text_chunk": "Process image in flow\nPromptFlow defines a contract to represent image data."} +{"text_chunk": "Data class\n`promptflow.contracts.multimedia.Image`\nImage 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."} +{"text_chunk": "Data type in flow input\nSet the type of flow input to `image` and promptflow will treat it as an image."} +{"text_chunk": "Reference image in prompt template\nIn 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`. In this case, `test_image` will be substituted with base64 or source_url (if set) before sending to LLM model."} +{"text_chunk": "Serialization/Deserialization\nPromptflow uses a special dict to represent image.\n`{\"data:image/;\": \"\"}`\n\n- `` can be html standard mime image types. Setting it to specific type can help previewing the image correctly, or it can be `*` for unknown type.\n- `` is the image serialized representation, there are 3 supported types:\n\n - url\n\n It can point to a public accessable web url. E.g.\n\n {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/logo-ms-social.png\"}\n - base64\n\n It can be the base64 encoding of the image. E.g.\n\n {\"data:image/png;base64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABLAQMAAAC81rD0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAAP7////DYP5JAAAAAWJLR0QB/wIt3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB+QIGBcKN7/nP/UAAAASSURBVDjLY2AYBaNgFIwCdAAABBoAAaNglfsAAAAZdEVYdGNvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVDnr0DLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI0VDIzOjEwOjU1KzAzOjAwkHdeuQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNFQyMzoxMDo1NSswMzowMOEq5gUAAAAASUVORK5CYII=\"}\n\n - path\n\n 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.\n\n {\"data:image/png;path\": \"./my-image.png\"}\n\nPlease note that `path` representation is not supported in Deployment scenario."} +{"text_chunk": "Batch Input data\nBatch input data containing image can be of 2 formats:\n1. 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.\n ```json\n {\"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\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;url\": \"https://developer.microsoft.com/_devcom/images/404.png\"}}\n ```\n2. 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:\n ```\n BatchInputFolder\n |----input.jsonl\n |----image1.png\n |----image2.png\n ```\n Content of `input.jsonl`\n ```json\n {\"question\": \"How many colors are there in the image?\", \"input_image\": {\"data:image/png;path\": \"image1.png\"}}\n {\"question\": \"What's this image about?\", \"input_image\": {\"data:image/png;path\": \"image2.png\"}}\n ```"} +{"text_chunk": "Quick Start\n\nThis guide will walk you through the fist step using of prompt flow code-first experience.\n\n**Prerequisite** - To make the most of this tutorial, you'll need:\n\n- Know how to program with Python :)\n- A basic understanding of Machine Learning can be beneficial, but it's not mandatory.\n\n\n**Learning Objectives** - Upon completing this tutorial, you should learn how to:\n- Setup your python environment to run prompt flow\n- Clone a sample flow & understand what's a flow\n- Understand how to edit the flow using visual editor or yaml\n- Test the flow using your favorite experience: CLI, SDK or VS Code Extension."} +{"text_chunk": "Set up your dev environment\n\n1. A python environment with version `python=3.9` or higher version like 3.10. It's recommended to use python environment manager miniconda. After you have installed miniconda, run below commands to create a python environment:\n```bash\nconda create --name pf python=3.9\nconda activate pf\n```\n\n2. Install `promptflow` and `promptflow-tools`.\n```sh\npip install promptflow promptflow-tools\n```\n\n3. Check the installation.\n```bash"} +{"text_chunk": "should print promptflow version, e.g. \"0.1.0b3\"\npf -v\n```"} +{"text_chunk": "Understand what's a flow\n\nA flow, represented as a YAML file, is a DAG of functions, which is connected via input/output dependencies, and executed based on the topology by prompt flow executor. See Flows for more details."} +{"text_chunk": "Get the flow sample\n\nClone the sample repo and check flows in folder examples/flows.\n\n```bash\ngit clone https://github.com/microsoft/promptflow.git\n```"} +{"text_chunk": "Understand flow directory\nThe sample used in this tutorial is the web-classification flow, which categorizes URLs into several predefined classes. Classification is a traditional machine learning task, and this sample illustrates how to perform classification using GPT and prompts.\n\n```bash\ncd promptflow/examples/flows/standard/web-classification\n```\n\nA flow directory is a directory that contains all contents of a flow. Structure of flow folder:\n- **flow.dag.yaml**: The flow definition with inputs/outputs, nodes, tools and variants for authoring purpose.\n- **.promptflow/flow.tools.json**: It contains tools meta referenced in `flow.dag.yaml`.\n- **Source code files (.py, .jinja2)**: User managed, the code scripts referenced by tools.\n- **requirements.txt**: Python package dependencies for this flow.\n\n\n!flow_dir\n\nIn order to run this specific flow, you need to install its requirements first.\n\n```sh\npip install -r requirements.txt\n```"} +{"text_chunk": "Understand the flow yaml\nThe entry file of a flow directory is `flow.dag.yaml` which describes the `DAG(Directed Acyclic Graph)` of a flow. Below is a sample of flow DAG:\n\n!flow_dag\n\nThis graph is rendered by VS Code extension which will be introduced in the next section."} +{"text_chunk": "Using VS Code Extension to visualize the flow\n_Note: Prompt flow VS Code Extension is highly recommended for flow development and debugging._\n\n1. Prerequisites for VS Code extension.\n - Install latest stable version of VS Code\n - Install VS Code Python extension\n\n2. Install Prompt flow for VS Code extension\n\n3. Select python interpreter\n\n !vscode\n !vscode\n\n\n2. Open dag in vscode. You can open the `flow.dag.yaml` as yaml file, or you can also open it in `visual editor`.\n !vscode"} +{"text_chunk": "Develop and test your flow"} +{"text_chunk": "How to edit the flow\n\nTo test your flow with varying input data, you have the option to modify the default input. If you are well-versed with the structure, you may also add or remove nodes to alter the flow's arrangement.\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json\ninputs:\n url:\n type: string\n # change the default value of input url here\n default: https://play.google.com/store/apps/details?id=com.twitter.android\n...\n```\nSee more details of this topic in Develop a flow."} +{"text_chunk": "Create necessary connections\n\n:::{note}\nIf you are using `WSL` or other OS without default keyring storage backend, you may encounter `StoreConnectionEncryptionKeyError`, please refer to FAQ for the solutions.\n:::\n\n\nThe `connection` helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n\nThe sample flow web-classification uses connection `open_ai_connection` inside, e.g. `classify_with_llm` node needs to talk to `llm` using the connection.\n\nWe need to set up the connection if we haven't added it before. Once created, the connection will be stored in local db and can be used in any flow.\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nFirstly we need a connection yaml file `connection.yaml`:\n\nIf you are using Azure Open AI, prepare your resource follow with this instruction and get your `api_key` if you don't have one.\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/AzureOpenAIConnection.schema.json\nname: open_ai_connection\ntype: azure_open_ai\napi_key: \napi_base: \napi_type: azure\napi_version: \n```\n\nIf you are using OpenAI, sign up account via OpenAI website, login and find personal API key, then use this yaml:\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/OpenAIConnection.schema.json\nname: open_ai_connection\ntype: open_ai\napi_key: \"\"\norganization: \"\" # optional\n```\nThen we can use CLI command to create the connection.\n\n```sh\npf connection create -f connection.yaml\n```\n\nMore command details can be found in CLI reference.\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nIn SDK, connections can be created and managed with `PFClient`.\n\n```python\nfrom promptflow import PFClient\nfrom promptflow.entities import AzureOpenAIConnection"} +{"text_chunk": "PFClient can help manage your runs and connections.\npf = PFClient()\n\ntry:\n conn_name = \"open_ai_connection\"\n conn = pf.connections.get(name=conn_name)\n print(\"using existing connection\")\nexcept:\n connection = AzureOpenAIConnection(\n name=conn_name,\n api_key=\"\",\n api_base=\"\",\n api_type=\"azure\",\n api_version=\"\",\n )\n\n # use this if you have an existing OpenAI account\n # from promptflow.entities import OpenAIConnection\n # connection = OpenAIConnection(\n # name=conn_name,\n # api_key=\"\",\n # )\n\n conn = pf.connections.create_or_update(connection)\n print(\"successfully created connection\")\n\nprint(conn)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\n\n\n1. Click the promptflow icon to enter promptflow control panel\n\n !vsc_add_connection\n\n2. Create your connection.\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n !vsc_add_connection\n\n\n:::\n\n::::\n\nLearn more on more actions like delete connection in: Manage connections."} +{"text_chunk": "Test the flow\n\n:::{admonition} Note\nTesting flow will NOT create a batch run record, therefore it's unable to use commands like `pf run show-details` to get the run information. If you want to persist the run record, see Run and evaluate a flow\n:::\n\n\nAssuming you are in working directory `promptflow/examples/flows/standard/`\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nChange the default input to the value you want to test.\n\n!q_0\n\n```sh\npf flow test --flow web-classification # \"web-classification\" is the directory name\n```\n\n!flow-test-output-cli\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\nThe return value of `test` function is the flow/node outputs.\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient()\n\nflow_path = \"web-classification\" # \"web-classification\" is the directory name"} +{"text_chunk": "Test flow\nflow_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\", \"answer\": \"Channel\", \"evidence\": \"Url\"} # The inputs of the flow.\nflow_result = pf.test(flow=flow_path, inputs=flow_inputs)\nprint(f\"Flow outputs: {flow_result}\")"} +{"text_chunk": "Test node in the flow\nnode_name = \"fetch_text_content_from_url\" # The node name in the flow.\nnode_inputs = {\"url\": \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"} # The inputs of the node.\nnode_result = pf.test(flow=flow_path, inputs=node_inputs, node=node_name)\nprint(f\"Node outputs: {node_result}\")\n```\n\n!Flow test outputs\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n\nUse the code lens action on the top of the yaml editor to trigger flow test\n!dag_yaml_flow_test\n\n\nClick the run flow button on the top of the visual editor to trigger flow test.\n!visual_editor_flow_test\n:::\n\n::::\n\nSee more details of this topic in Initialize and test a flow."} +{"text_chunk": "Next steps\n\nLearn more on how to:\n- Develop a flow: details on how to develop a flow by writing a flow yaml from scratch.\n- Initialize and test a flow: details on how develop a flow from scratch or existing code.\n- Add conditional control to a flow: how to use activate config to add conditional control to a flow.\n- Run and evaluate a flow: run and evaluate the flow using multi line data file.\n- Deploy a flow: how to deploy the flow as a web app.\n- Manage connections: how to manage the endpoints/secrets information to access external services including LLMs.\n- Prompt flow in Azure AI: run and evaluate flow in Azure AI where you can collaborate with team better.\n\nAnd you can also check our examples, especially:\n- Getting started with prompt flow: the notebook covering the python sdk experience for sample introduced in this doc.\n- Tutorial: Chat with PDF: An end-to-end tutorial on how to build a high quality chat application with prompt flow, including flow development and evaluation with metrics."} +{"text_chunk": "Use column mapping\n\nIn this document, we will introduce how to map inputs with column mapping when running a flow."} +{"text_chunk": "Column mapping introduction\n\nColumn mapping is a mapping from flow input name to specified values.\nIf specified, the flow will be executed with provided value for specified inputs.\nThe following types of values in column mapping are supported:\n\n- `${data.}` to reference from your test dataset.\n- `${run.outputs.}` to reference from referenced run's output. **Note**: this only supported when `--run` is provided for `pf run`.\n- `STATIC_VALUE` to create static value for all lines for specified column."} +{"text_chunk": "Flow inputs override priority\n\nFlow input values are overridden according to the following priority:\n\n\"specified in column mapping\" > \"default value\" > \"same name column in provided data\".\n\nFor example, if we have a flow with following inputs:\n\n```yaml\ninputs:\n input1:\n type: string\n default: \"default_val1\"\n input2:\n type: string\n default: \"default_val2\"\n input3:\n type: string\n input4:\n type: string\n...\n```\n\nAnd the flow will return each inputs in outputs.\n\nWith the following data\n\n```json\n{\"input3\": \"val3_in_data\", \"input4\": \"val4_in_data\"}\n```\n\nAnd use the following YAML to run\n\n```yaml\n$schema: https://azuremlschemas.azureedge.net/promptflow/latest/Run.schema.json\nflow: path/to/flow"} +{"text_chunk": "my_flow has default value val2 for key2\ndata: path/to/data"} +{"text_chunk": "my_data has column key3 with value val3\ncolumn_mapping:\n input1: \"val1_in_column_mapping\"\n input3: ${data.input3}\n```\n\nSince the flow will return each inputs in output, we can get the actual inputs from `outputs.output` field in run details:\n\n!column_mapping_details\n\n- Input \"input1\" has value \"val1_in_column_mapping\" since it's specified as constance in `column_mapping`.\n- Input \"input2\" has value \"default_val2\" since it used default value in flow dag.\n- Input \"input3\" has value \"val3_in_data\" since it's specified as data reference in `column_mapping`.\n- Input \"input4\" has value \"val4_in_data\" since it has same name column in provided data."} +{"text_chunk": "Set global configs\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nPromptflow supports setting global configs to avoid passing the same parameters to each command. The global configs are stored in a yaml file, which is located at `~/.promptflow/pf.yaml` by default.\n\nThe config file is shared between promptflow extension and sdk/cli. Promptflow extension controls each config through UI, so the following sections will show how to set global configs using promptflow cli."} +{"text_chunk": "Set config\n```shell\npf config set =\n```\nFor example:\n```shell\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```"} +{"text_chunk": "Show config\nThe following command will get all configs and show them as json format:\n```shell\npf config show\n```\nAfter running the above config set command, show command will return the following result:\n```json\n{\n \"connection\": {\n \"provider\": \"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n }\n}\n```"} +{"text_chunk": "Supported configs\nThe connection provider, default to \"local\". There are 3 possible provider values."} +{"text_chunk": "local\nSet connection provider to local with `connection.provider=local`.\n\nConnections will be saved locally. `PFClient`(or `pf connection` commands) will manage local connections. Consequently, the flow will be executed using these local connections."} +{"text_chunk": "full azure machine learning workspace resource id\nSet connection provider to a specific workspace with:\n```\nconnection.provider=azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\n```\n\nWhen `get` or `list` connections, `PFClient`(or `pf connection` commands) will return workspace connections, and flow will be executed using these workspace connections.\n_Secrets for workspace connection will not be shown by those commands, which means you may see empty dict `{}` for custom connections._\n\n:::{note}\nCommand `create`, `update` and `delete` are not supported for workspace connections, please manage it in workspace portal, az ml cli or AzureML SDK.\n:::"} +{"text_chunk": "azureml\nIn addition to the full resource id, you can designate the connection provider as \"azureml\" with `connection.provider=azureml`. In this case,\npromptflow will attempt to retrieve the workspace configuration by searching `.azureml/config.json` from the current directory, then progressively from its parent folders. So it's possible to set the workspace configuration for different flow by placing the config file in the project folder.\n\nThe expected format of the config file is as follows:\n```json\n{\n \"workspace_name\": \"\",\n \"resource_group\": \"\",\n \"subscription_id\": \"\"\n}\n\n```\n\n> \ud83d\udca1 Tips\n> In addition to the CLI command line setting approach, we also support setting this connection provider through the VS Code extension UI. Click here to learn more."} +{"text_chunk": "Tune prompts using variants\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nTo better understand this part, please read Quick start and Run and evaluate a flow first."} +{"text_chunk": "What is variant and why should we care\n\nIn order to help users tune the prompts in a more efficient way, we introduce the concept of variants which can help you test the model\u2019s behavior under different conditions, such as different wording, formatting, context, temperature, or top-k, compare and find the best prompt and configuration that maximizes the model\u2019s accuracy, diversity, or coherence."} +{"text_chunk": "Create a run with different variant node\n\n In this example, we use the flow web-classification, its node `summarize_text_content` has two variants: `variant_0` and `variant_1`. The difference between them is the inputs parameters:\n\n\n```yaml\n...\nnodes:\n- name: summarize_text_content\n use_variants: true\n...\nnode_variants:\n summarize_text_content:\n default_variant_id: variant_0\n variants:\n variant_0:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '128'\n temperature: '0.2'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n variant_1:\n node:\n type: llm\n source:\n type: code\n path: summarize_text_content__variant_1.jinja2\n inputs:\n deployment_name: text-davinci-003\n max_tokens: '256'\n temperature: '0.3'\n text: ${fetch_text_content_from_url.output}\n provider: AzureOpenAI\n connection: open_ai_connection\n api: completion\n module: promptflow.tools.aoai\n```\n\nYou can check the whole flow definition in flow.dag.yaml.\n\nNow we will create a variant run which uses node `summarize_text_content`'s variant `variant_1`. \nAssuming you are in working directory `/examples/flows/standard`\n\n\n::::{tab-set}\n\n:::{tab-item} CLI\n:sync: CLI\n\nNote we pass `--variant` to specify which variant of the node should be running.\n\n```sh\npf run create --flow web-classification --data web-classification/data.jsonl --variant '${summarize_text_content.variant_1}' --column-mapping url='${data.url}' --stream --name my_first_variant_run\n```\n\n:::\n\n:::{tab-item} SDK\n:sync: SDK\n\n```python\nfrom promptflow import PFClient\n\npf = PFClient() # get a promptflow client\nflow = \"web-classification\"\ndata= \"web-classification/data.jsonl\""} +{"text_chunk": "use the variant1 of the summarize_text_content node.\nvariant_run = pf.run(\n flow=flow,\n data=data,\n variant=\"${summarize_text_content.variant_1}\", # use variant 1.\n column_mapping={\"url\": \"${data.url}\"},\n)\n\npf.stream(variant_run)\n```\n:::\n\n:::{tab-item} VS Code Extension\n:sync: VS Code Extension\n!img\n!img\n:::\n\n::::\n\nAfter the variant run is created, you can evaluate the variant run with a evaluation flow, just like you evalute a standard flow run."} +{"text_chunk": "Next steps\n\nLearn more about:\n- Run and evaluate a flow\n- Deploy a flow\n- Prompt flow in Azure AI"} +{"text_chunk": "Azure AI Language\nAzure AI Language enables users with task-oriented and optimized pre-trained language models to effectively understand documents and conversations. This Prompt flow tool is a wrapper for various Azure AI Language APIs. The current list of supported capabilities is as follows:\n\n| Name | Description |\n|-------------------------------------------|-------------------------------------------------------|\n| Abstractive Summarization | Generate abstractive summaries from documents. |\n| Extractive Summarization | Extract summaries from documents. |\n| Conversation Summarization | Summarize conversations. |\n| Entity Recognition | Recognize and categorize entities in documents. |\n| Key Phrase Extraction | Extract key phrases from documents. |\n| Language Detection | Detect the language of documents. |\n| PII Entity Recognition | Recognize and redact PII entities in documents. |\n| Sentiment Analysis | Analyze the sentiment of documents. |\n| Conversational Language Understanding | Predict intents and entities from user's utterances. |\n| Translator | Translate documents. |"} +{"text_chunk": "Requirements\n- For AzureML users: \n follow this wiki, starting from `Prepare runtime`. Note that the PyPi package name is `promptflow-azure-ai-language`.\n- For local users: \n ```\n pip install promptflow-azure-ai-language\n ```"} +{"text_chunk": "Prerequisites\nThe tool calls APIs from Azure AI Language. To use it, you must create a connection to an Azure AI Language resource. Create a Language resource first, if necessary.\n- In Prompt flow, add a new `CustomConnection`.\n - Under the `secrets` field, specify the resource's API key: `api_key: `\n - Under the `configs` field, specify the resource's endpoint: `endpoint: `\n\nTo use the `Translator` tool, you must set up an additional connection to an Azure AI Translator resource. Create a Translator resource first, if necessary.\n- In Prompt flow, add a new `CustomConnection`.\n - Under the `secrets` field, specify the resource's API key: `api_key: `\n - Under the `configs` field, specify the resource's endpoint: `endpoint: `\n - If your Translator Resource is regional and non-global, specify its region under `configs` as well: `region: `"} +{"text_chunk": "Inputs\nThe tool accepts the following inputs:\n\n- **Abstractive Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | query | string | The query used to structure summarization. | Yes |\n | summary_length | string (enum) | The desired summary length. Enum values are `short`, `medium`, and `long`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Extractive Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | query | string | The query used to structure summarization. | Yes |\n | sentence_count | int | The desired number of output summary sentences. Default value is `3`. | No |\n | sort_by | string (enum) | The sorting criteria for extractive summarization results. Enum values are `Offset` to sort results in order of appearance in the text and `Rank` to sort results in order of importance (i.e. rank score) according to model. Default value is `Offset`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Conversation Summarization**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. Text should be of the following form: `: \\n : \\n ...` | Yes |\n | modality | string (enum) | The modality of the input text. Enum values are `text` for input from a text source, and `transcript` for input from a transcript source. | Yes |\n | summary_aspect | string (enum) | The desired summary \"aspect\" to obtain. Enum values are `chapterTitle` to obtain the chapter title of any conversation, `issue` to obtain the summary of issues in transcripts of web chats and service calls between customer-service agents and customers, `narrative` to obtain the generic summary of any conversation, `resolution` to obtain the summary of resolutions in transcripts of web chats and service calls between customer-service agents and customers, `recap` to obtain a general summary, and `follow-up tasks` to obtain a summary of follow-up or action items. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Entity Recognition**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Key Phrase Extraction**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text."} +{"text_chunk": "| Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Language Detection**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | text | string | The input text. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **PII Entity Recognition**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | domain | string (enum) | The PII domain used for PII Entity Recognition. Enum values are `none` for no domain, or `phi` to indicate that entities in the Personal Health domain should be redacted. Default value is `none`. | No |\n | categories | list[string] | Describes the PII categories to return. Default value is `[]`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Sentiment Analysis**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | text | string | The input text. | Yes |\n | opinion_mining | bool | Should opinion mining be enabled. Default value is `False`. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Conversational Language Understanding**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Language resource. | Yes |\n | language | string | The ISO 639-1 code for the language of the input. | Yes |\n | utterances | string | A single user utterance or a json array of user utterances. | Yes |\n | project_name | string | The Conversational Language Understanding project to be called. | Yes |\n | deployment_name | string | The Conversational Language Understanding project deployment to be called. | Yes |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |\n\n- **Translator**:\n | Name | Type | Description | Required |\n |--------------------|------------------|-------------|----------|\n | connection | CustomConnection | The created connection to an Azure AI Translator resource. | Yes |\n | text | string | The input text. | Yes |\n | to | list[string] | The languages to translate the input text to. | Yes |\n | source_language | string | The language of the input text. | No |\n | parse_response | bool | Should the raw API json output be parsed. Default value is `False`. | No |"} +{"text_chunk": "Outputs\nIf the input parameter `parse_response` is set to `False` (default value), the raw API json output will be returned as a string. Refer to the REST API reference for details on API output. For Conversational Language Understanding, the output will be a list of raw API json responses, one response for each user utterance in the input. \n\nWhen `parse_response` is set to `True`, the tool will parse API output as follows:\n\n\n| Name | Type | Description |\n|-------------------------------------------------------------|--------|---------------------|\n| Abstractive Summarization | string | Abstractive summary. |\n| Extractive Summarization | list[string] | Extracted summary sentence strings. |\n| Conversation Summarization | string | Conversation summary based on `summary_aspect`. |\n| Entity Recognition | dict[string, string] | Recognized entities, where keys are entity names and values are entity categories. |\n| Key Phrase Extraction | list[string] | Extracted key phrases as strings. |\n| Language Detection | string | Detected language's ISO 639-1 code. |\n| PII Entity Recognition | string | Input `text` with PII entities redacted. |\n| Sentiment Analysis | string | Analyzed sentiment: `positive`, `neutral`, or `negative`. |\n| Conversational Language Understanding | list[dict[string, string]] | List of user utterances and associated intents. |\n| Translator | dict[string, string] | Translated text, where keys are the translated languages and values are the translated texts. |"} +{"text_chunk": "Flow YAML Schema\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe source JSON schema can be found at Flow.schema.json"} +{"text_chunk": "YAML syntax\n\n| Key | Type | Description |\n|----------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `$schema` | string | The YAML schema. If you use the prompt flow VS Code extension to author the YAML file, including `$schema` at the top of your file enables you to invoke schema and resource completions. |\n| `inputs` | object | Dictionary of flow inputs. The key is a name for the input within the context of the flow and the value is the flow input definition. |\n| `inputs.` | object | The flow input definition. See Flow input for the set of configurable properties. |\n| `outputs` | object | Dictionary of flow outputs. The key is a name for the output within the context of the flow and the value is the flow output definition. |\n| `outputs.` | object | The component output definition. See Flow output for the set of configurable properties. |\n| `nodes` | array | Sets of dictionary of individual nodes to run as steps within the flow. Node can use built-in tool or third-party tool. See Nodes for more information. |\n| `node_variants` | object | Dictionary of nodes with variants. The key is the node name and value contains variants definition and `default_variant_id`. See Node variants for more information. |\n| `environment` | object | The environment to use for the flow. The key can be `image` or `python_requirements_txt` and the value can be either a image or a python requirements text file. |\n| `additional_includes` | array | Additional includes is a list of files that can be shared among flows. Users can specify additional files and folders used by flow, and prompt flow will help copy them all to the snapshot during flow creation. |"} +{"text_chunk": "Flow input\n\n| Key | Type | Description | Allowed values |\n|-------------------|-------------------------------------------|------------------------------------------------------|-----------------------------------------------------|\n| `type` | string | The type of flow input. | `int`, `double`, `bool`, `string`, `list`, `object`, `image` |\n| `description` | string | Description of the input. | |\n| `default` | int, double, bool, string, list, object, image | The default value for the input. | |\n| `is_chat_input` | boolean | Whether the input is the chat flow input. | |\n| `is_chat_history` | boolean | Whether the input is the chat history for chat flow. | |"} +{"text_chunk": "Flow output\n\n| Key | Type | Description | Allowed values |\n|------------------|---------|-------------------------------------------------------------------------------|-----------------------------------------------------|\n| `type` | string | The type of flow output. | `int`, `double`, `bool`, `string`, `list`, `object` |\n| `description` | string | Description of the output. | |\n| `reference` | string | A reference to the node output, e.g. ${.output.} | |\n| `is_chat_output` | boolean | Whether the output is the chat flow output. | |"} +{"text_chunk": "Nodes\nNodes is a set of node which is a dictionary with following fields. Below, we only show the common fields of a single node using built-in tool.\n\n| Key | Type | Description | Allowed values |\n|----------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|\n| `name` | string | The name of the node. | |\n| `type` | string | The type of the node. | Type of built-in tool like `Python`, `Prompt`, `LLM` and third-party tool like `Vector Search`, etc. |\n| `inputs` | object | Dictionary of node inputs. The key is the input name and the value can be primitive value or a reference to the flow input or the node output, e.g. `${inputs.}`, `${.output}` or `${.output.}` | |\n| `source` | object | Dictionary of tool source used by the node. The key contains `type`, `path` and `tool`. The type can be `code`, `package` and `package_with_prompt`. | |\n| `provider` | string | It indicates the provider of the tool. Used when the `type` is LLM. | `AzureOpenAI` or `OpenAI` |\n| `connection` | string | The connection name which has been created before. Used when the `type` is LLM. | |\n| `api` | string | The api name of the provider. Used when the `type` is LLM. | |\n| `module` | string | The module name of the tool using by the node. Used when the `type` is LLM. | |\n| `use_variants` | bool | Whether the node has variants. | |"} +{"text_chunk": "Node variants\nNode variants is a dictionary containing variants definition for nodes with variants with their respective node names as dictionary keys.\nBelow, we explore the variants for a single node.\n\n| Key | Type | Description | Allowed values |\n|----------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|\n| `` | string | The name of the node. | |\n| `default_variant_id` | string | Default variant id. | |\n| `variants ` | object | This dictionary contains all node variations, with the variant id serving as the key and a node definition dictionary as the corresponding value. Within the node definition dictionary, the key labeled 'node' should contain a variant definition similar to Nodes, excluding the 'name' field. | |"} +{"text_chunk": "Examples\n\nFlow examples are available in the GitHub repository.\n\n- basic\n- web-classification\n- basic-chat\n- chat-with-pdf\n- eval-basic"} +{"text_chunk": "pf\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nManage prompt flow resources with the prompt flow CLI.\n\n| Command | Description |\n|---------------------------------|---------------------------------|\n| pf flow | Manage flows. |\n| pf connection | Manage connections. |\n| pf run | Manage runs. |\n| pf tool | Init or list tools. |\n| pf config | Manage config for current user. |"} +{"text_chunk": "pf flow\n\nManage promptflow flow flows.\n\n| Command | Description |\n| --- | --- |\n| pf flow init | Initialize a prompt flow directory. |\n| pf flow test | Test the prompt flow or flow node. |\n| pf flow validate | Validate a flow and generate `flow.tools.json` for it. |\n| pf flow build | Build a flow for further sharing or deployment. |\n| pf flow serve | Serve a flow as an endpoint. |"} +{"text_chunk": "pf flow init\n\nInitialize a prompt flow directory.\n\n```bash\npf flow init [--flow]\n [--entry]\n [--function]\n [--prompt-template]\n [--type]\n [--yes]\n```"} +{"text_chunk": "Examples\n\nCreate a flow folder with code, prompts and YAML specification of the flow.\n\n```bash\npf flow init --flow \n```\n\nCreate an evaluation prompt flow\n\n```bash\npf flow init --flow --type evaluation\n```\n\nCreate a flow in existing folder\n\n```bash\npf flow init --flow --entry --function --prompt-template \n```"} +{"text_chunk": "Optional Parameters\n\n`--flow`\n\nThe flow name to create.\n\n`--entry`\n\nThe entry file name.\n\n`--function`\n\nThe function name in entry file.\n\n`--prompt-template`\n\nThe prompt template parameter and assignment.\n\n`--type`\n\nThe initialized flow type. \naccepted value: standard, evaluation, chat\n\n`--yes --assume-yes -y`\n\nAutomatic yes to all prompts; assume 'yes' as answer to all prompts and run non-interactively."} +{"text_chunk": "pf flow test\n\nTest the prompt flow or flow node.\n\n```bash\npf flow test --flow\n [--inputs]\n [--node]\n [--variant]\n [--debug]\n [--interactive]\n [--verbose]\n```"} +{"text_chunk": "Examples\n\nTest the flow.\n\n```bash\npf flow test --flow \n```\n\nTest the flow with single line from input file.\n\n```bash\npf flow test --flow --inputs data_key1=data_val1 data_key2=data_val2\n```\n\nTest the flow with specified variant node.\n\n```bash\npf flow test --flow --variant '${node_name.variant_name}'\n```\n\nTest the single node in the flow.\n\n```bash\npf flow test --flow --node \n```\n\nDebug the single node in the flow.\n\n```bash\npf flow test --flow --node --debug\n```\n\nChat in the flow.\n\n```bash\npf flow test --flow --node --interactive\n```"} +{"text_chunk": "Required Parameter\n\n`--flow`\n\nThe flow directory to test."} +{"text_chunk": "Optional Parameters\n\n`--inputs`\n\nInput data for the flow. Example: --inputs data1=data1_val data2=data2_val\n\n`--node`\n\nThe node name in the flow need to be tested.\n\n`--variant`\n\nNode & variant name in format of ${node_name.variant_name}.\n\n`--debug`\n\nDebug the single node in the flow.\n\n`--interactive`\n\nStart a interactive chat session for chat flow.\n\n`--verbose`\n\nDisplays the output for each step in the chat flow."} +{"text_chunk": "pf flow validate\n\nValidate the prompt flow and generate a `flow.tools.json` under `.promptflow`. This file is required when using flow as a component in a Azure ML pipeline.\n\n```bash\npf flow validate --source\n [--debug]\n [--verbose]\n```"} +{"text_chunk": "Examples\n\nValidate the flow.\n\n```bash\npf flow validate --source \n```"} +{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow source to validate."} +{"text_chunk": "pf flow build\n\nBuild a flow for further sharing or deployment.\n\n```bash\npf flow build --source\n --output\n --format\n [--variant]\n [--verbose]\n [--debug]\n```"} +{"text_chunk": "Examples\n\nBuild a flow as docker, which can be built into Docker image via `docker build`.\n\n```bash\npf flow build --source --output --format docker\n```\n\nBuild a flow as docker with specific variant.\n\n```bash\npf flow build --source --output --format docker --variant '${node_name.variant_name}'\n```"} +{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow or run source to be used.\n\n`--output`\n\nThe folder to output built flow. Need to be empty or not existed.\n\n`--format`\n\nThe format to build flow into"} +{"text_chunk": "Optional Parameters\n\n`--variant`\n\nNode & variant name in format of ${node_name.variant_name}.\n\n`--verbose`\n\nShow more details for each step during build.\n\n`--debug`\n\nShow debug information during build."} +{"text_chunk": "pf flow serve\n\nServing a flow as an endpoint.\n\n```bash\npf flow serve --source\n [--port]\n [--host]\n [--environment-variables]\n [--verbose]\n [--debug]\n```"} +{"text_chunk": "Examples\n\nServe flow as an endpoint.\n\n```bash\npf flow serve --source \n```\n\nServe flow as an endpoint with specific port and host.\n\n```bash\npf flow serve --source --port --host --environment-variables key1=\"`${my_connection.api_key}`\" key2=\"value2\"\n```"} +{"text_chunk": "Required Parameter\n\n`--source`\n\nThe flow or run source to be used."} +{"text_chunk": "Optional Parameters\n\n`--port`\n\nThe port on which endpoint to run.\n\n`--host`\n\nThe host of endpoint.\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example: --environment-variable key1=\"\\`${my_connection.api_key}\\`\" key2=\"value2\". The value reference to connection keys will be resolved to the actual value, and all environment variables specified will be set into `os.environ`.\n\n`--verbose`\n\nShow more details for each step during serve.\n\n`--debug`\n\nShow debug information during serve."} +{"text_chunk": "pf connection\n\nManage prompt flow connections.\n\n| Command | Description |\n| --- | --- |\n| pf connection create | Create a connection. |\n| pf connection update | Update a connection. |\n| pf connection show | Show details of a connection. |\n| pf connection list | List all the connection. |\n| pf connection delete | Delete a connection. |"} +{"text_chunk": "pf connection create\n\nCreate a connection.\n\n```bash\npf connection create --file\n [--name]\n [--set]\n```"} +{"text_chunk": "Examples\n\nCreate a connection with YAML file.\n\n```bash\npf connection create -f \n```\n\nCreate a connection with YAML file with override.\n\n```bash\npf connection create -f --set api_key=\"\"\n```\n\nCreate a custom connection with .env file; note that overrides specified by `--set` will be ignored.\n\n```bash\npf connection create -f .env --name \n```"} +{"text_chunk": "Required Parameter\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow connection specification."} +{"text_chunk": "Optional Parameters\n\n`--name -n`\n\nName of the connection.\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} +{"text_chunk": "pf connection update\n\nUpdate a connection.\n\n```bash\npf connection update --name\n [--set]\n```"} +{"text_chunk": "Example\n\nUpdate a connection.\n\n```bash\npf connection update -n --set api_key=\"\"\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} +{"text_chunk": "Optional Parameter\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} +{"text_chunk": "pf connection show\n\nShow details of a connection.\n\n```bash\npf connection show --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} +{"text_chunk": "pf connection list\n\nList all the connection.\n\n```bash\npf connection list\n```"} +{"text_chunk": "pf connection delete\n\nDelete a connection.\n\n```bash\npf connection delete --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the connection."} +{"text_chunk": "pf run\n\nManage prompt flow runs.\n\n| Command | Description |\n| --- | --- |\n| pf run create | Create a run. |\n| pf run update | Update a run metadata, including display name, description and tags. |\n| pf run stream | Stream run logs to the console. |\n| pf run list | List runs. |\n| pf run show | Show details for a run. |\n| pf run show-details | Preview a run's intput(s) and output(s). |\n| pf run show-metrics | Print run metrics to the console. |\n| pf run visualize | Visualize a run. |\n| pf run archive | Archive a run. |\n| pf run restore | Restore an archived run. |"} +{"text_chunk": "pf run create\n\nCreate a run.\n\n```bash\npf run create [--file]\n [--flow]\n [--data]\n [--column-mapping]\n [--run]\n [--variant]\n [--stream]\n [--environment-variables]\n [--connections]\n [--set]\n [--source]\n```"} +{"text_chunk": "Examples\n\nCreate a run with YAML file.\n\n```bash\npf run create -f \n```\n\nCreate a run from flow directory and reference a run.\n\n```bash\npf run create --flow --data --column-mapping groundtruth='${data.answer}' prediction='${run.outputs.category}' --run --variant '${summarize_text_content.variant_0}' --stream\n```\n\nCreate a run from an existing run record folder.\n\n```bash\npf run create --source \n```"} +{"text_chunk": "Optional Parameters\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow run specification; can be overwritten by other parameters. Reference here for YAML schema.\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--data`\n\nLocal path to the data file.\n\n`--column-mapping`\n\nInputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns.\n\n`--run`\n\nReferenced flow run name. For example, you can run an evaluation flow against an existing run. For example, \"pf run create --flow evaluation_flow_dir --run existing_bulk_run\".\n\n`--variant`\n\nNode & variant name in format of `${node_name.variant_name}`.\n\n`--stream -s`\n\nIndicates whether to stream the run's logs to the console. \ndefault value: False\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example:\n`--environment-variable key1='${my_connection.api_key}' key2='value2'`. The value reference\nto connection keys will be resolved to the actual value, and all environment variables\nspecified will be set into os.environ.\n\n`--connections`\n\nOverwrite node level connections with provided value.\nExample: `--connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo`\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\nExample: `--set property1.property2=`.\n\n`--source`\n\nLocal path to the existing run record folder."} +{"text_chunk": "pf run update\n\nUpdate a run metadata, including display name, description and tags.\n\n```bash\npf run update --name\n [--set]\n```"} +{"text_chunk": "Example\n\nUpdate a run\n\n```bash\npf run update -n --set display_name=\"\" description=\"\" tags.key=\"value\"\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "Optional Parameter\n\n`--set`\n\nUpdate an object by specifying a property path and value to set. Example: --set property1.property2=."} +{"text_chunk": "pf run stream\n\nStream run logs to the console.\n\n```bash\npf run stream --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf run list\n\nList runs.\n\n```bash\npf run list [--all-results]\n [--archived-only]\n [--include-archived]\n [--max-results]\n```"} +{"text_chunk": "Optional Parameters\n\n`--all-results`\n\nReturns all results. \ndefault value: False\n\n`--archived-only`\n\nList archived runs only. \ndefault value: False\n\n`--include-archived`\n\nList archived runs and active runs. \ndefault value: False\n\n`--max-results -r`\n\nMax number of results to return. Default is 50. \ndefault value: 50"} +{"text_chunk": "pf run show\n\nShow details for a run.\n\n```bash\npf run show --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf run show-details\n\nPreview a run's input(s) and output(s).\n\n```bash\npf run show-details --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf run show-metrics\n\nPrint run metrics to the console.\n\n```bash\npf run show-metrics --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf run visualize\n\nVisualize a run in the browser.\n\n```bash\npf run visualize --names\n```"} +{"text_chunk": "Required Parameter\n\n`--names -n`\n\nName of the runs, comma separated."} +{"text_chunk": "pf run archive\n\nArchive a run.\n\n```bash\npf run archive --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf run restore\n\nRestore an archived run.\n\n```bash\npf run restore --name\n```"} +{"text_chunk": "Required Parameter\n\n`--name -n`\n\nName of the run."} +{"text_chunk": "pf tool\n\nManage promptflow tools.\n\n| Command | Description |\n| --- | --- |\n| pf tool init | Initialize a tool directory. |\n| pf tool list | List all tools in the environment. |\n| pf tool validate | Validate tools. |"} +{"text_chunk": "pf tool init\n\nInitialize a tool directory.\n\n```bash\npf tool init [--package]\n [--tool]\n [--set]\n```"} +{"text_chunk": "Examples\n\nCreating a package tool from scratch.\n\n```bash\npf tool init --package --tool \n```\n\nCreating a package tool with extra info.\n\n```bash\npf tool init --package --tool --set icon= category= tags=\"{'': ''}\"\n```\n\nCreating a package tool from scratch.\n\n```bash\npf tool init --package --tool \n```\n\nCreating a python tool from scratch.\n\n```bash\npf tool init --tool \n```"} +{"text_chunk": "Optional Parameters\n\n`--package`\n\nThe package name to create.\n\n`--tool`\n\nThe tool name to create.\n\n`--set`\n\nSet extra information about the tool, like category, icon and tags. Example: --set =."} +{"text_chunk": "pf tool list\n\nList all tools in the environment.\n\n```bash\npf tool list [--flow]\n```"} +{"text_chunk": "Examples\n\nList all package tool in the environment.\n\n```bash\npf tool list\n```\n\nList all package tool and code tool in the flow.\n\n```bash\npf tool list --flow \n```"} +{"text_chunk": "Optional Parameters\n\n`--flow`\n\nThe flow directory."} +{"text_chunk": "pf tool validate\n\nValidate tool.\n\n```bash\npf tool validate --source\n```"} +{"text_chunk": "Examples\n\nValidate single function tool.\n\n```bash\npf tool validate -\u2013source ..\n```\n\nValidate all tool in a package tool.\n\n```bash\npf tool validate -\u2013source \n```\n\nValidate tools in a python script.\n\n```bash\npf tool validate --source \n```"} +{"text_chunk": "Required Parameter\n\n`--source`\n\nThe tool source to be used."} +{"text_chunk": "pf config\n\nManage config for current user.\n\n| Command | Description |\n|-----------------------------------|--------------------------------------------|\n| pf config set | Set prompt flow configs for current user. |\n| pf config show | Show prompt flow configs for current user. |"} +{"text_chunk": "pf config set\n\nSet prompt flow configs for current user, configs will be stored at ~/.promptflow/pf.yaml.\n\n```bash\npf config set\n```"} +{"text_chunk": "Examples\n\nConfig connection provider to azure workspace for current user.\n\n```bash\npf config set connection.provider=\"azureml://subscriptions//resourceGroups//providers/Microsoft.MachineLearningServices/workspaces/\"\n```"} +{"text_chunk": "pf config show\n\nShow prompt flow configs for current user.\n\n```bash\npf config show\n```"} +{"text_chunk": "Examples\n\nShow prompt flow for current user.\n\n```bash\npf config show\n```"} +{"text_chunk": "pfazure\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nManage prompt flow resources on Azure with the prompt flow CLI.\n\n| Command | Description |\n| --- | --- |\n| pfazure flow | Manage flows. |\n| pfazure run | Manage runs. |"} +{"text_chunk": "pfazure flow\n\nManage flows.\n\n| Command | Description |\n| --- | --- |\n| pfazure flow create | Create a flow. |\n| pfazure flow list | List flows in a workspace. |"} +{"text_chunk": "pfazure flow create\n\nCreate a flow in Azure AI from a local flow folder.\n\n```bash\npfazure flow create [--flow]\n [--set]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\n- `display_name`: Flow display name that will be created in remote. Default to be flow folder name + timestamp if not specified.\n- `type`: Flow type. Default to be \"standard\" if not specified. Available types are: \"standard\", \"evaluation\", \"chat\".\n- `description`: Flow description. e.g. \"--set description=\\.\"\n- `tags`: Flow tags. e.g. \"--set tags.key1=value1 tags.key2=value2.\"\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure flow list\n\nList remote flows on Azure AI.\n\n```bash\npfazure flow list [--max-results]\n [--include-others]\n [--type]\n [--output]\n [--archived-only]\n [--include-archived]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n [--output]\n```"} +{"text_chunk": "Parameters\n\n`--max-results -r`\n\nMax number of results to return. Default is 50, upper bound is 100.\n\n`--include-others`\n\nInclude flows created by other owners. By default only flows created by the current user are returned.\n\n`--type`\n\nFilter flows by type. Available types are: \"standard\", \"evaluation\", \"chat\".\n\n`--archived-only`\n\nList archived flows only.\n\n`--include-archived`\n\nList archived flows and active flows.\n\n`--output -o`\n\nOutput format. Allowed values: `json`, `table`. Default: `json`.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run\n\nManage prompt flow runs.\n\n| Command | Description |\n| --- | --- |\n| pfazure run create | Create a run. |\n| pfazure run list | List runs in a workspace. |\n| pfazure run show | Show details for a run. |\n| pfazure run stream | Stream run logs to the console. |\n| pfazure run show-details | Show a run details. |\n| pfazure run show-metrics | Show run metrics. |\n| pfazure run visualize | Visualize a run. |\n| pfazure run archive | Archive a run. |\n| pfazure run restore | Restore a run. |\n| pfazure run update | Update a run. |\n| pfazure run download | Download a run. |"} +{"text_chunk": "pfazure run create\n\nCreate a run.\n\n```bash\npfazure run create [--file]\n [--flow]\n [--data]\n [--column-mapping]\n [--run]\n [--variant]\n [--stream]\n [--environment-variables]\n [--connections]\n [--set]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--file -f`\n\nLocal path to the YAML file containing the prompt flow run specification; can be overwritten by other parameters. Reference here for YAML schema.\n\n`--flow`\n\nLocal path to the flow directory.\n\n`--data`\n\nLocal path to the data file or remote data. e.g. azureml:name:version.\n\n`--column-mapping`\n\nInputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns.\n\n`--run`\n\nReferenced flow run name. For example, you can run an evaluation flow against an existing run. For example, \"pfazure run create --flow evaluation_flow_dir --run existing_bulk_run --column-mapping url='${data.url}'\".\n\n`--variant`\n\nNode & variant name in format of `${node_name.variant_name}`.\n\n`--stream -s`\n\nIndicates whether to stream the run's logs to the console. \ndefault value: False\n\n`--environment-variables`\n\nEnvironment variables to set by specifying a property path and value. Example:\n`--environment-variable key1='${my_connection.api_key}' key2='value2'`. The value reference\nto connection keys will be resolved to the actual value, and all environment variables\nspecified will be set into os.environ.\n\n`--connections`\n\nOverwrite node level connections with provided value.\nExample: `--connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo`\n\n`--set`\n\nUpdate an object by specifying a property path and value to set.\nExample: `--set property1.property2=`.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run list\n\nList runs in a workspace.\n\n```bash\npfazure run list [--archived-only]\n [--include-archived]\n [--max-results]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--archived-only`\n\nList archived runs only. \ndefault value: False\n\n`--include-archived`\n\nList archived runs and active runs. \ndefault value: False\n\n`--max-results -r`\n\nMax number of results to return. Default is 50, upper bound is 100. \ndefault value: 50\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run show\n\nShow details for a run.\n\n```bash\npfazure run show --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run stream\n\nStream run logs to the console.\n\n```bash\npfazure run stream --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run show-details\n\nShow a run details.\n\n```bash\npfazure run show-details --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run show-metrics\n\nShow run metrics.\n\n```bash\npfazure run show-metrics --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run visualize\n\nVisualize a run.\n\n```bash\npfazure run visualize --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run archive\n\nArchive a run.\n\n```bash\npfazure run archive --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run restore\n\nRestore a run.\n\n```bash\npfazure run restore --name\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run update\n\nUpdate a run's metadata, such as `display name`, `description` and `tags`.\n\n```bash\npfazure run update --name\n [--set display_name=\"\" description=\"\" tags.key=\"\"]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Examples\n\nSet `display name`, `description` and `tags`:\n\n```bash\npfazure run update --name --set display_name=\"\" description=\"\" tags.key=\"\"\n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--set`\n\nSet meta information of the run, like `display_name`, `description` or `tags`. Example: --set =.\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "pfazure run download\n\nDownload a run's metadata, such as `input`, `output`, `snapshot` and `artifact`. After the download is finished, you can use `pf run create --source ` to register this run as a local run record, then you can use commands like `pf run show/visualize` to inspect the run just like a run that was created from local flow.\n\n```bash\npfazure run download --name\n [--output]\n [--overwrite]\n [--subscription]\n [--resource-group]\n [--workspace-name]\n```"} +{"text_chunk": "Examples\n\nDownload a run data to local:\n```bash\npfazure run download --name --output \n```"} +{"text_chunk": "Parameters\n\n`--name -n`\n\nName of the run.\n\n`--output -o`\n\nOutput folder path to store the downloaded run data. Default to be `~/.promptflow/.runs` if not specified\n\n`--overwrite`\n\nOverwrite the existing run data if the output folder already exists. Default to be `False` if not specified\n\n`--subscription`\n\nSubscription id, required when there is no default value from `az configure`.\n\n`--resource-group -g`\n\nResource group name, required when there is no default value from `az configure`.\n\n`--workspace-name -w`\n\nWorkspace name, required when there is no default value from `az configure`."} +{"text_chunk": "PLACEHOLDER"} +{"text_chunk": "Run YAML Schema\n\n:::{admonition} Experimental feature\nThis is an experimental feature, and may change at any time. Learn more.\n:::\n\nThe source JSON schema can be found at Run.schema.json"} +{"text_chunk": "YAML syntax\n\n| Key | Type | Description |\n|-------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `$schema` | string | The YAML schema. If you use the prompt flow VS Code extension to author the YAML file, including $schema at the top of your file enables you to invoke schema and resource completions. |\n| `name` | string | The name of the run. |\n| `flow` | string | Path of the flow directory. |\n| `description` | string | Description of the run. |\n| `display_name` | string | Display name of the run. |\n| `runtime` | string | The runtime for the run. Only supported for cloud run. |\n| `data` | string | Input data for the run. Local path or remote uri(starts with azureml: or public URL) are supported. Note: remote uri is only supported for cloud run. |\n| `run` | string | Referenced flow run name. For example, you can run an evaluation flow against an existing run. |\n| `column_mapping` | object | Inputs column mapping, use `${data.xx}` to refer to data columns, use `${run.inputs.xx}` to refer to referenced run's data columns, and `${run.outputs.xx}` to refer to run outputs columns. |\n| `connections` | object | Overwrite node level connections with provided value. Example: --connections node1.connection=test_llm_connection node1.deployment_name=gpt-35-turbo |\n| `environment_variables` | object/string | Environment variables to set by specifying a property path and value. Example: `{\"key1\"=\"${my_connection.api_key}\"}`. The value reference to connection keys will be resolved to the actual value, and all environment variables specified will be set into os.environ. |\n| `properties` | object | Dictionary of properties of the run. |\n| `tags` | object | Dictionary of tags of the run. |\n| `resources` | object | Dictionary of resources used for automatic runtime. Only supported for cloud run. See Resources Schema for the set of configurable properties. |\n| `variant` | string | The variant for the run. |\n| `status` | string | The status of the run. Only available for when getting an existing run. Won't take affect if set when creating a run. |"} +{"text_chunk": "Resources Schema\n\n| Key | Type | Description |\n|-------------------------------------|---------|-------------------------------------------------------------|\n| `instance_type` | string | The instance type for automatic runtime of the run. |\n| `idle_time_before_shutdown_minutes` | integer | The idle time before automatic runtime shutdown in minutes. |"} +{"text_chunk": "Examples\n\nRun examples are available in the GitHub repository.\n\n- basic\n- web-classification\n- flow-with-additional-includes"} +{"text_chunk": "Azure OpenAI GPT-4 Turbo with Vision"} +{"text_chunk": "Introduction\nAzure OpenAI GPT-4 Turbo with Vision tool enables you to leverage your AzureOpenAI GPT-4 Turbo with Vision model deployment to analyze images and provide textual responses to questions about them."} +{"text_chunk": "Prerequisites\n\n- Create AzureOpenAI resources\n\n Create Azure OpenAI resources with instruction\n\n- Create a GPT-4 Turbo with Vision deployment\n\n Browse to Azure OpenAI Studio and sign in with the credentials associated with your Azure OpenAI resource. During or after the sign-in workflow, select the appropriate directory, Azure subscription, and Azure OpenAI resource.\n\n Under Management select Deployments and Create a GPT-4 Turbo with Vision deployment by selecting model name: `gpt-4` and model version `vision-preview`."} +{"text_chunk": "Connection\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| AzureOpenAI | Required | Required | Required | Required |"} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| connection | AzureOpenAI | the AzureOpenAI connection to be used in the tool | Yes |\n| deployment\\_name | string | the language model to use | Yes |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is 512. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |"} +{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| string | The text of one response of conversation |"} +{"text_chunk": "Content Safety (Text)\n\nAzure Content Safety is a content moderation service developed by Microsoft that help users detect harmful content from different modalities and languages. This tool is a wrapper for the Azure Content Safety Text API, which allows you to detect text content and get moderation results. See the Azure Content Safety for more information."} +{"text_chunk": "Requirements\n\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users,\n `pip install promptflow-tools`\n> [!NOTE]\n> Content Safety (Text) tool is now incorporated into the latest `promptflow-tools` package. If you have previously installed the package `promptflow-contentsafety`, please uninstall it to avoid the duplication in your local tool list."} +{"text_chunk": "Prerequisites\n\n- Create an Azure Content Safety resource.\n- Add \"Azure Content Safety\" connection in prompt flow. Fill \"API key\" field with \"Primary key\" from \"Keys and Endpoint\" section of created resource."} +{"text_chunk": "Inputs\n\nYou can use the following parameters as inputs for this tool:\n\n| Name | Type | Description | Required |\n| ---- | ---- | ----------- | -------- |\n| text | string | The text that need to be moderated. | Yes |\n| hate_category | string | The moderation sensitivity for Hate category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for hate category. The other three options mean different degrees of strictness in filtering out hate content. The default option is *medium_sensitivity*. | Yes |\n| sexual_category | string | The moderation sensitivity for Sexual category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for sexual category. The other three options mean different degrees of strictness in filtering out sexual content. The default option is *medium_sensitivity*. | Yes |\n| self_harm_category | string | The moderation sensitivity for Self-harm category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for self-harm category. The other three options mean different degrees of strictness in filtering out self_harm content. The default option is *medium_sensitivity*. | Yes |\n| violence_category | string | The moderation sensitivity for Violence category. You can choose from four options: *disable*, *low_sensitivity*, *medium_sensitivity*, or *high_sensitivity*. The *disable* option means no moderation for violence category. The other three options mean different degrees of strictness in filtering out violence content. The default option is *medium_sensitivity*. | Yes |\n\nFor more information, please refer to Azure Content Safety"} +{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool:\n\n\n Output\n \n```json\n{\n \"action_by_category\": {\n \"Hate\": \"Accept\",\n \"SelfHarm\": \"Accept\",\n \"Sexual\": \"Accept\",\n \"Violence\": \"Accept\"\n },\n \"suggested_action\": \"Accept\"\n }\n```\n\n\n\nThe `action_by_category` field gives you a binary value for each category: *Accept* or *Reject*. This value shows if the text meets the sensitivity level that you set in the request parameters for that category.\n\nThe `suggested_action` field gives you an overall recommendation based on the four categories. If any category has a *Reject* value, the `suggested_action` will be *Reject* as well."} +{"text_chunk": "Embedding"} +{"text_chunk": "Introduction\nOpenAI's embedding models convert text into dense vector representations for various NLP tasks. See the OpenAI Embeddings API for more information."} +{"text_chunk": "Prerequisite\nCreate OpenAI resources:\n\n- **OpenAI**\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- **Azure OpenAI (AOAI)**\n\n Create Azure OpenAI resources with instruction"} +{"text_chunk": "**Connections**\n\nSetup connections to provide resources in embedding tool.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| OpenAI | Required | Required | - | - |\n| AzureOpenAI | Required | Required | Required | Required |"} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|-----------------------------------------------------------------------|----------|\n| input | string | the input text to embed | Yes |\n| connection | string | the connection for the embedding tool use to provide resources | Yes |\n| model/deployment_name | string | instance of the text-embedding engine to use. Fill in model name if you use OpenAI connection, or deployment name if use Azure OpenAI connection. | Yes |"} +{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| list | The vector representations for inputs |\n\nThe following is an example response returned by the embedding tool:\n\n\n Output\n \n```\n[-0.005744616035372019,\n-0.007096089422702789,\n-0.00563855143263936,\n-0.005272455979138613,\n-0.02355326898396015,\n0.03955197334289551,\n-0.014260607771575451,\n-0.011810848489403725,\n-0.023170066997408867,\n-0.014739611186087132,\n...]\n```"} +{"text_chunk": "Faiss Index Lookup\n\nFaiss Index Lookup is a tool tailored for querying within a user-provided Faiss-based vector store. In combination with our Large Language Model (LLM) tool, it empowers users to extract contextually relevant information from a domain knowledge base."} +{"text_chunk": "Requirements\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users, if your index is stored in local path,\n \n `pip install promptflow-vectordb`\n \n if your index is stored in Azure storage,\n\n `pip install promptflow-vectordb[azure]`"} +{"text_chunk": "Prerequisites\n - step 1. Prepare an accessible path on Azure Blob Storage. Here's the guide if a new storage account needs to be created: Azure Storage Account.\n - step 2. Create related Faiss-based index files on Azure Blob Storage. We support the LangChain format (index.faiss + index.pkl) for the index files, which can be prepared either by employing our promptflow-vectordb SDK or following the quick guide from LangChain documentation. Please refer to the instructions of An example code for creating Faiss index for building index using promptflow-vectordb SDK.\n - step 3. Based on where you put your own index files, the identity used by the promptflow runtime should be granted with certain roles. Please refer to Steps to assign an Azure role:\n\n | Location | Role |\n | ---- | ---- |\n | workspace datastores or workspace default blob | AzureML Data Scientist |\n | other blobs | Storage Blob Data Reader |"} +{"text_chunk": "For local users,\n - Create Faiss-based index files in local path by only doing step 2 above."} +{"text_chunk": "Inputs\n\nThe tool accepts the following inputs:\n\n| Name | Type | Description | Required |\n| ---- | ---- | ----------- | -------- |\n| path | string | URL or path for the vector store.local path (for local users):`` Azure blob URL format (with [azure] extra installed):https://``.blob.core.windows.net/``/``.AML datastore URL format (with [azure] extra installed):azureml://subscriptions/``/resourcegroups/``/workspaces/``/data/``public http/https URL (for public demonstration):http(s)://`` | Yes |\n| vector | list[float] | The target vector to be queried, which can be generated by the LLM tool. | Yes |\n| top_k | integer | The count of top-scored entities to return. Default value is 3. | No |"} +{"text_chunk": "Outputs\n\nThe following is an example for JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by our promptflow-vectordb SDK. For the Faiss Index Search, the following fields are populated:\n\n| Field Name | Type | Description |\n| ---- | ---- | ----------- |\n| text | string | Text of the entity |\n| score | float | Distance between the entity and the query vector |\n| metadata | dict | Customized key-value pairs provided by user when create the index |\n\n\n Output\n \n```json\n[\n {\n \"metadata\": {\n \"link\": \"http://sample_link_0\",\n \"title\": \"title0\"\n },\n \"original_entity\": null,\n \"score\": 0,\n \"text\": \"sample text #0\",\n \"vector\": null\n },\n {\n \"metadata\": {\n \"link\": \"http://sample_link_1\",\n \"title\": \"title1\"\n },\n \"original_entity\": null,\n \"score\": 0.05000000447034836,\n \"text\": \"sample text #1\",\n \"vector\": null\n },\n {\n \"metadata\": {\n \"link\": \"http://sample_link_2\",\n \"title\": \"title2\"\n },\n \"original_entity\": null,\n \"score\": 0.20000001788139343,\n \"text\": \"sample text #2\",\n \"vector\": null\n }\n]\n\n```"} +{"text_chunk": "LLM"} +{"text_chunk": "Introduction\nPrompt flow LLM tool enables you to leverage widely used large language models like OpenAI or Azure OpenAI (AOAI) for natural language processing. \n\nPrompt flow provides a few different LLM APIs:\n- **Completion**: OpenAI's completion models generate text based on provided prompts.\n- **Chat**: OpenAI's chat models facilitate interactive conversations with text-based inputs and responses.\n> [!NOTE]\n> We now remove the `embedding` option from LLM tool api setting. You can use embedding api with Embedding tool."} +{"text_chunk": "Prerequisite\nCreate OpenAI resources:\n\n- **OpenAI**\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- **Azure OpenAI (AOAI)**\n\n Create Azure OpenAI resources with instruction"} +{"text_chunk": "**Connections**\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY | API Type | API Version |\n|-------------|----------|----------|----------|-------------|\n| OpenAI | Required | Required | - | - |\n| AzureOpenAI | Required | Required | Required | Required |"} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|-----------------------------------------------------------------------------------------|----------|\n| prompt | string | text prompt that the language model will complete | Yes |\n| model, deployment_name | string | the language model to use | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the completion. Default is 16. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| suffix | string | text appended to the end of the completion | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| logprobs | integer | the number of log probabilities to generate. Default is null. | No |\n| echo | boolean | value that indicates whether to echo back the prompt in the response. Default is false. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |\n| best\\_of | integer | the number of best completions to generate. Default is 1. | No |\n| logit\\_bias | dictionary | the logit bias for the language model. Default is empty dictionary. | No |"} +{"text_chunk": "Chat\n\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| prompt | string | text prompt that the language model will response | Yes |\n| model, deployment_name | string | the language model to use | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is inf. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0.| No |\n| logit\\_bias | dictionary | the logit bias for the language model. Default is empty dictionary. | No |\n| function\\_call | object | value that controls which function is called by the model. Default is null. | No |\n| functions | list | a list of functions the model may generate JSON inputs for. Default is null. | No |\n| response_format | object | an object specifying the format that the model must output. Default is null. | No |"} +{"text_chunk": "Outputs\n\n| API | Return Type | Description |\n|------------|-------------|------------------------------------------|\n| Completion | string | The text of one predicted completion |\n| Chat | string | The text of one response of conversation |"} +{"text_chunk": "How to use LLM Tool?\n\n1. Setup and select the connections to OpenAI resources\n2. Configure LLM model api and its parameters\n3. Prepare the Prompt with guidance."} +{"text_chunk": "Open Model LLM"} +{"text_chunk": "Introduction\n\nThe Open Model LLM tool enables the utilization of a variety of Open Model and Foundational Models, such as Falcon and Llama 2, for natural language processing in Azure ML Prompt Flow.\n\nHere's how it looks in action on the Visual Studio Code prompt flow extension. In this example, the tool is being used to call a LlaMa-2 chat endpoint and asking \"What is CI?\".\n\n!Screenshot of the Open Model LLM On VScode Prompt Flow extension\n\nThis prompt flow tool supports two different LLM API types:\n\n- **Chat**: Shown in the example above. The chat API type facilitates interactive conversations with text-based inputs and responses.\n- **Completion**: The Completion API type is used to generate single response text completions based on provided prompt input."} +{"text_chunk": "Quick Overview: How do I use Open Model LLM Tool?\n\n1. Choose a Model from the AzureML Model Catalog and get it deployed.\n2. Connect to the model deployment.\n3. Configure the open model llm tool settings.\n4. Prepare the Prompt with guidance.\n5. Run the flow."} +{"text_chunk": "Prerequisites: Model Deployment\n\n1. Pick the model which matched your scenario from the Azure Machine Learning model catalog.\n2. Use the \"Deploy\" button to deploy the model to a AzureML Online Inference endpoint.\n2.1. Use one of the Pay as you go deployment options.\n\nMore detailed instructions can be found here Deploying foundation models to endpoints for inferencing."} +{"text_chunk": "Prerequisites: Connect to the Model\n\nIn order for prompt flow to use your deployed model, you will need to connect to it. There are several ways to connect."} +{"text_chunk": "1. Endpoint Connections\n\nOnce associated to a AzureML or Azure AI Studio workspace, the Open Model LLM tool can use the endpoints on that workspace.\n\n1. **Using AzureML or Azure AI Studio workspaces**: If you are using prompt flow in one of the web page based browsers workspaces, the online endpoints available on that workspace will automatically who up.\n\n2. **Using VScode or Code First**: If you are using prompt flow in VScode or one of the Code First offerings, you will need to connect to the workspace. The Open Model LLM tool uses the azure.identity DefaultAzureCredential client for authorization. One way is through setting environment credential values."} +{"text_chunk": "2. Custom Connections\n\nThe Open Model LLM tool uses the CustomConnection. Prompt flow supports two types of connections:\n\n1. **Workspace Connections** - These are connections which are stored as secrets on an Azure Machine Learning workspace. While these can be used, in many places, the are commonly created and maintained in the Studio UI.\n\n2. **Local Connections** - These are connections which are stored locally on your machine. These connections are not available in the Studio UX's, but can be used with the VScode extension.\n\nInstructions on how to create a workspace or local Custom Connection can be found here.\n\nThe required keys to set are:\n\n1. **endpoint_url**\n - This value can be found at the previously created Inferencing endpoint.\n2. **endpoint_api_key**\n - Ensure to set this as a secret value.\n - This value can be found at the previously created Inferencing endpoint.\n3. **model_family**\n - Supported values: LLAMA, DOLLY, GPT2, or FALCON\n - This value is dependent on the type of deployment you are targeting."} +{"text_chunk": "Running the Tool: Inputs\n\nThe Open Model LLM tool has a number of parameters, some of which are required. Please see the below table for details, you can match these to the screen shot above for visual clarity.\n\n| Name | Type | Description | Required |\n|------|------|-------------|----------|\n| api | string | This is the API mode and will depend on the model used and the scenario selected. *Supported values: (Completion \\| Chat)* | Yes |\n| endpoint_name | string | Name of an Online Inferencing Endpoint with a supported model deployed on it. Takes priority over connection. | No |\n| temperature | float | The randomness of the generated text. Default is 1. | No |\n| max_new_tokens | integer | The maximum number of tokens to generate in the completion. Default is 500. | No |\n| top_p | float | The probability of using the top choice from the generated tokens. Default is 1. | No |\n| model_kwargs | dictionary | This input is used to provide configuration specific to the model used. For example, the Llama-02 model may use {\\\"temperature\\\":0.4}. *Default: {}* | No |\n| deployment_name | string | The name of the deployment to target on the Online Inferencing endpoint. If no value is passed, the Inferencing load balancer traffic settings will be used. | No |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |"} +{"text_chunk": "Outputs\n\n| API | Return Type | Description |\n|------------|-------------|------------------------------------------|\n| Completion | string | The text of one predicted completion |\n| Chat | string | The text of one response int the conversation |"} +{"text_chunk": "Deploying to an Online Endpoint\n\nWhen deploying a flow containing the Open Model LLM tool to an online endpoint, there is an additional step to setup permissions. During deployment through the web pages, there is a choice between System-assigned and User-assigned Identity types. Either way, using the Azure Portal (or a similar functionality), add the \"Reader\" Job function role to the identity on the Azure Machine Learning workspace or Ai Studio project which is hosting the endpoint. The prompt flow deployment may need to be refreshed."} +{"text_chunk": "OpenAI GPT-4V"} +{"text_chunk": "Introduction\nOpenAI GPT-4V tool enables you to leverage OpenAI's GPT-4 with vision, also referred to as GPT-4V or gpt-4-vision-preview in the API, to take images as input and answer questions about them."} +{"text_chunk": "Prerequisites\n\n- Create OpenAI resources\n\n Sign up account OpenAI website\n Login and Find personal API key\n\n- Get Access to GPT-4 API\n\n To use GPT-4 with vision, you need access to GPT-4 API. Learn more about How to get access to GPT-4 API"} +{"text_chunk": "Connection\n\nSetup connections to provisioned resources in prompt flow.\n\n| Type | Name | API KEY |\n|-------------|----------|----------|\n| OpenAI | Required | Required |"} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|------------------------|-------------|------------------------------------------------------------------------------------------------|----------|\n| connection | OpenAI | the OpenAI connection to be used in the tool | Yes |\n| model | string | the language model to use, currently only support gpt-4-vision-preview | Yes |\n| prompt | string | The text prompt that the language model will use to generate it's response. | Yes |\n| max\\_tokens | integer | the maximum number of tokens to generate in the response. Default is 512. | No |\n| temperature | float | the randomness of the generated text. Default is 1. | No |\n| stop | list | the stopping sequence for the generated text. Default is null. | No |\n| top_p | float | the probability of using the top choice from the generated tokens. Default is 1. | No |\n| presence\\_penalty | float | value that controls the model's behavior with regards to repeating phrases. Default is 0. | No |\n| frequency\\_penalty | float | value that controls the model's behavior with regards to generating rare phrases. Default is 0. | No |"} +{"text_chunk": "Outputs\n\n| Return Type | Description |\n|-------------|------------------------------------------|\n| string | The text of one response of conversation |"} +{"text_chunk": "Prompt"} +{"text_chunk": "Introduction\nThe Prompt Tool in PromptFlow offers a collection of textual templates that serve as a starting point for creating prompts. \nThese templates, based on the Jinja2 template engine, facilitate the definition of prompts. The tool proves useful \nwhen prompt tuning is required prior to feeding the prompts into the Language Model (LLM) model in PromptFlow."} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|--------------------|--------|----------------------------------------------------------|----------|\n| prompt | string | The prompt template in Jinja | Yes |\n| Inputs | - | List of variables of prompt template and its assignments | - |"} +{"text_chunk": "Outputs\n\nThe prompt text parsed from the prompt + Inputs"} +{"text_chunk": "How to write Prompt?\n\n1. Prepare jinja template. Learn more about Jinja\n\n_In below example, the prompt incorporates Jinja templating syntax to dynamically generate the welcome message and personalize it based on the user's name. It also presents a menu of options for the user to choose from. Depending on whether the user_name variable is provided, it either addresses the user by name or uses a generic greeting._\n\n```jinja\nWelcome to {{ website_name }}!\n{% if user_name %}\n Hello, {{ user_name }}!\n{% else %}\n Hello there!\n{% endif %}\nPlease select an option from the menu below:\n1. View your account\n2. Update personal information\n3. Browse available products\n4. Contact customer support\n```\n\n2. Assign value for the variables.\n\n_In above example, two variables would be automatically detected and listed in '**Inputs**' section. Please assign values._"} +{"text_chunk": "Sample 1\nInputs\n\n| Variable | Type | Sample Value | \n|---------------|--------|--------------|\n| website_name | string | \"Microsoft\" |\n| user_name | string | \"Jane\" |\n\nOutputs\n\n```\nWelcome to Microsoft! Hello, Jane! Please select an option from the menu below: 1. View your account 2. Update personal information 3. Browse available products 4. Contact customer support\n```"} +{"text_chunk": "Sample 2\n\nInputs\n\n| Variable | Type | Sample Value | \n|--------------|--------|----------------|\n| website_name | string | \"Bing\" |\n| user_name | string | \" |\n\nOutputs\n\n```\nWelcome to Bing! Hello there! Please select an option from the menu below: 1. View your account 2. Update personal information 3. Browse available products 4. Contact customer support\n```"} +{"text_chunk": "Python"} +{"text_chunk": "Introduction\nUsers are empowered by the Python Tool to offer customized code snippets as self-contained executable nodes in PromptFlow.\nUsers can effortlessly create Python tools, edit code, and verify results with ease."} +{"text_chunk": "Inputs\n\n| Name | Type | Description | Required |\n|--------|--------|------------------------------------------------------|---------|\n| Code | string | Python code snippet | Yes |\n| Inputs | - | List of tool function parameters and its assignments | - |"} +{"text_chunk": "Types\n\n| Type | Python example | Description |\n|-----------------------------------------------------|---------------------------------|--------------------------------------------|\n| int | param: int | Integer type |\n| bool | param: bool | Boolean type |\n| string | param: str | String type |\n| double | param: float | Double type |\n| list | param: list or param: List[T] | List type |\n| object | param: dict or param: Dict[K, V] | Object type |\n| Connection | param: CustomConnection | Connection type, will be handled specially |\n\n\nParameters with `Connection` type annotation will be treated as connection inputs, which means:\n- Promptflow extension will show a selector to select the connection.\n- During execution time, promptflow will try to find the connection with the name same from parameter value passed in.\n\nNote that `Union[...]` type annotation is supported **ONLY** for connection type,\nfor example, `param: Union[CustomConnection, OpenAIConnection]`."} +{"text_chunk": "Outputs\n\nThe return of the python tool function."} +{"text_chunk": "How to write Python Tool?"} +{"text_chunk": "Guidelines\n\n1. Python Tool Code should consist of a complete Python code, including any necessary module imports.\n\n2. Python Tool Code must contain a function decorated with @tool (tool function), serving as the entry point for execution. The @tool decorator should be applied only once within the snippet.\n\n _Below sample defines python tool \"my_python_tool\", decorated with @tool_\n\n3. Python tool function parameters must be assigned in 'Inputs' section\n\n _Below sample defines inputs \"message\" and assign with \"world\"_\n\n4. Python tool function shall have return\n\n _Below sample returns a concatenated string_"} +{"text_chunk": "Code\n\nThe snippet below shows the basic structure of a tool function. Promptflow will read the function and extract inputs\nfrom function parameters and type annotations.\n\n```python\nfrom promptflow import tool\nfrom promptflow.connections import CustomConnection"} +{"text_chunk": "The inputs section will change based on the arguments of the tool function, after you save the code\n@tool\ndef my_python_tool(message: str, my_conn: CustomConnection) -> str:\n my_conn_dict = dict(my_conn)\n # Do some function call with my_conn_dict...\n return 'hello ' + message\n```"} +{"text_chunk": "Inputs\n\n| Name | Type | Sample Value in Flow Yaml | Value passed to function|\n|---------|--------|-------------------------| ------------------------|\n| message | string | \"world\" | \"world\" |\n| my_conn | CustomConnection | \"my_conn\" | CustomConnection object |\n\nPromptflow will try to find the connection named 'my_conn' during execution time."} +{"text_chunk": "outputs\n\n```python\n\"hello world\"\n```"} +{"text_chunk": "Keyword Arguments Support\nStarting from version 1.0.0 of PromptFlow and version 1.4.0 of Prompt flow for VS Code,\nwe have introduced support for keyword arguments (kwargs) in the Python tool.\n\n\n```python\nfrom promptflow import tool\n\n\n@tool\ndef print_test(normal_input: str, **kwargs):\n for key, value in kwargs.items():\n print(f\"Key {key}'s value is {value}\")\n return len(kwargs)\n\n```\nWhen you add `kwargs` in your python tool like above code, you can insert variable number of inputs by the `+Add input` button.\n\n!Screenshot of the kwargs On VScode Prompt Flow extension"} +{"text_chunk": "SerpAPI"} +{"text_chunk": "Introduction\n\nThe SerpAPI API is a Python tool that provides a wrapper to the SerpAPI Google Search Engine Results API and [SerpApi Bing Search Engine Results API\n](https://serpapi.com/bing-search-api). \nWe could use the tool to retrieve search results from a number of different search engines, including Google and Bing, and you can specify a range of search parameters, such as the search query, location, device type, and more."} +{"text_chunk": "Prerequisite\n\nSign up at SERP API homepage"} +{"text_chunk": "Connection\nConnection is the model used to establish connections with Serp API.\n\n| Type | Name | API KEY |\n|-------------|----------|----------|\n| Serp | Required | Required |\n\n_**API Key** is on SerpAPI account dashboard_"} +{"text_chunk": "Inputs\n\nThe **serp api** tool supports following parameters:\n\n\n| Name | Type | Description | Required |\n|----------|---------|---------------------------------------------------------------|----------|\n| query | string | The search query to be executed. | Yes |\n| engine | string | The search engine to use for the search. Default is 'google'. | Yes |\n| num | integer | The number of search results to return.Default is 10. | No |\n| location | string | The geographic location to execute the search from. | No |\n| safe | string | The safe search mode to use for the search. Default is 'off'. | No |"} +{"text_chunk": "Outputs\nThe json representation from serpapi query.\n\n| Engine | Return Type | Output |\n|----------|-------------|-------------------------------------------------------|\n| google | json | Sample |\n| bing | json | Sample |"} +{"text_chunk": "Vector DB Lookup\n\nVector DB Lookup is a vector search tool that allows users to search top k similar vectors from vector database. This tool is a wrapper for multiple third-party vector databases. The list of current supported databases is as follows.\n\n| Name | Description |\n| --- | --- |\n| Azure Cognitive Search | Microsoft's cloud search service with built-in AI capabilities that enrich all types of information to help identify and explore relevant content at scale. |\n| Qdrant | Qdrant is a vector similarity search engine that provides a production-ready service with a convenient API to store, search and manage points (i.e. vectors) with an additional payload. |\n| Weaviate | Weaviate is an open source vector database that stores both objects and vectors. This allows for combining vector search with structured filtering. |\n\nThis tool will support more vector databases."} +{"text_chunk": "Requirements\n- For AzureML users, the tool is installed in default image, you can use the tool without extra installation.\n- For local users,\n\n `pip install promptflow-vectordb`"} +{"text_chunk": "Prerequisites\n\nThe tool searches data from a third-party vector database. To use it, you should create resources in advance and establish connection between the tool and the resource.\n\n - **Azure Cognitive Search:**\n - Create resource Azure Cognitive Search.\n - Add \"Cognitive search\" connection. Fill \"API key\" field with \"Primary admin key\" from \"Keys\" section of created resource, and fill \"API base\" field with the URL, the URL format is `https://{your_serive_name}.search.windows.net`.\n\n - **Qdrant:**\n - Follow the installation to deploy Qdrant to a self-maintained cloud server.\n - Add \"Qdrant\" connection. Fill \"API base\" with your self-maintained cloud server address and fill \"API key\" field.\n\n - **Weaviate:**\n - Follow the installation to deploy Weaviate to a self-maintained instance.\n - Add \"Weaviate\" connection. Fill \"API base\" with your self-maintained instance address and fill \"API key\" field."} +{"text_chunk": "Inputs\n\nThe tool accepts the following inputs:\n- **Azure Cognitive Search:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | CognitiveSearchConnection | The created connection for accessing to Cognitive Search endpoint. | Yes |\n | index_name | string | The index name created in Cognitive Search resource. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | vector_field | string | The vector field name. The target vector is searched in this vector field. | Yes |\n | search_params | dict | The search parameters. It's key-value pairs. Except for parameters in the tool input list mentioned above, additional search parameters can be formed into a JSON object as search_params. For example, use `{\"select\": \"\"}` as search_params to select the returned fields, use `{\"search\": \"\"}` to perform a hybrid search. | No |\n | search_filters | dict | The search filters. It's key-value pairs, the input format is like `{\"filter\": \"\"}` | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |\n\n- **Qdrant:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | QdrantConnection | The created connection for accessing to Qdrant server. | Yes |\n | collection_name | string | The collection name created in self-maintained cloud server. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | search_params | dict | The search parameters can be formed into a JSON object as search_params. For example, use `{\"params\": {\"hnsw_ef\": 0, \"exact\": false, \"quantization\": null}}` to set search_params. | No |\n | search_filters | dict | The search filters. It's key-value pairs, the input format is like `{\"filter\": {\"should\": [{\"key\": \"\", \"match\": {\"value\": \"\"}}]}}` | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |\n\n- **Weaviate:**\n\n | Name | Type | Description | Required |\n | ---- | ---- | ----------- | -------- |\n | connection | WeaviateConnection | The created connection for accessing to Weaviate. | Yes |\n | class_name | string | The class name. | Yes |\n | text_field | string | The text field name. The returned text field will populate the text of output. | No |\n | vector | list | The target vector to be queried, which can be generated by Embedding tool. | Yes |\n | top_k | int | The count of top-scored entities to return. Default value is 3 | No |"} +{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by promptflow-vectordb SDK. \n- **Azure Cognitive Search:**\n\n For Azure Cognitive Search, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | @search.score from the original entity, which evaluates the similarity between the entity and the query vector |\n | text | string | text of the entity|\n | vector | list | vector of the entity|\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"@search.score\": 0.5099789,\n \"id\": \"\",\n \"your_text_filed_name\": \"sample text1\",\n \"your_vector_filed_name\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972],\n \"your_additional_field_name\": \"\"\n },\n \"score\": 0.5099789,\n \"text\": \"sample text1\",\n \"vector\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972]\n }\n ]\n ```\n \n\n- **Qdrant:**\n\n For Qdrant, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | metadata | dict | payload from the original entity|\n | score | float | score from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text of the payload|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": {\n \"text\": \"sample text1\"\n },\n \"original_entity\": {\n \"id\": 1,\n \"payload\": {\n \"text\": \"sample text1\"\n },\n \"score\": 1,\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673],\n \"version\": 0\n },\n \"score\": 1,\n \"text\": \"sample text1\",\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673]\n }\n ]\n ```\n \n\n- **Weaviate:**\n\n For Weaviate, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | certainty from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text in the original entity|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"_additional\": {\n \"certainty\": 1,\n \"distance\": 0,\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n },\n \"text\": \"sample text1.\"\n },\n \"score\": 1,\n \"text\": \"sample text1.\",\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n }\n ]\n ```"} +{"text_chunk": "Outputs\n\nThe following is an example JSON format response returned by the tool, which includes the top-k scored entities. The entity follows a generic schema of vector search result provided by promptflow-vectordb SDK. \n- **Azure Cognitive Search:**\n\n For Azure Cognitive Search, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | @search.score from the original entity, which evaluates the similarity between the entity and the query vector |\n | text | string | text of the entity|\n | vector | list | vector of the entity|\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"@search.score\": 0.5099789,\n \"id\": \"\",\n \"your_text_filed_name\": \"sample text1\",\n \"your_vector_filed_name\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972],\n \"your_additional_field_name\": \"\"\n },\n \"score\": 0.5099789,\n \"text\": \"sample text1\",\n \"vector\": [-0.40517663431890405, 0.5856996257406859, -0.1593078462266455, -0.9776269170785785, -0.6145604369828972]\n }\n ]\n ```\n \n\n- **Qdrant:**\n\n For Qdrant, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | metadata | dict | payload from the original entity|\n | score | float | score from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text of the payload|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": {\n \"text\": \"sample text1\"\n },\n \"original_entity\": {\n \"id\": 1,\n \"payload\": {\n \"text\": \"sample text1\"\n },\n \"score\": 1,\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673],\n \"version\": 0\n },\n \"score\": 1,\n \"text\": \"sample text1\",\n \"vector\": [0.18257418, 0.36514837, 0.5477226, 0.73029673]\n }\n ]\n ```\n \n\n- **Weaviate:**\n\n For Weaviate, the following fields are populated:\n | Field Name | Type | Description |\n | ---- | ---- | ----------- |\n | original_entity | dict | the original response json from search REST API|\n | score | float | certainty from the original entity, which evaluates the similarity between the entity and the query vector|\n | text | string | text in the original entity|\n | vector | list | vector of the entity|\n\n \n Output\n \n ```json\n [\n {\n \"metadata\": null,\n \"original_entity\": {\n \"_additional\": {\n \"certainty\": 1,\n \"distance\": 0,\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n },\n \"text\": \"sample text1.\"\n },\n \"score\": 1,\n \"text\": \"sample text1.\",\n \"vector\": [\n 0.58,\n 0.59,\n 0.6,\n 0.61,\n 0.62\n ]\n }\n ]\n ```"} From e50e6f83e0cafea84895971f5ff5f3cf3a87eb2f Mon Sep 17 00:00:00 2001 From: cs_lucky Date: Thu, 18 Jan 2024 11:59:46 +0800 Subject: [PATCH 011/112] refine template --- .../test_data_gen/construct_test_data_flow/flow.dag.yaml | 8 +++----- examples/test_data_gen/construct_test_data_flow/utils.py | 6 +++--- .../validate_context_prompt.jinja2 | 4 +++- .../validate_question_prompt.jinja2 | 4 +--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml index 8421c55de3d..76635613e20 100644 --- a/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml +++ b/examples/test_data_gen/construct_test_data_flow/flow.dag.yaml @@ -1,6 +1,4 @@ $schema: https://azuremlschemas.azureedge.net/promptflow/latest/Flow.schema.json -id: template_standard_flow -name: Template Standard Flow environment: python_requirements_txt: requirements.txt inputs: @@ -94,7 +92,7 @@ nodes: type: code path: validate_and_generate_seed_question.py inputs: - connection: azure_open_ai_connection + connection: azure_openai_connection model: gpt-35-turbo validate_context_prompt: ${validate_context_prompt.output} seed_question_prompt: ${seed_question_prompt.output} @@ -105,7 +103,7 @@ nodes: type: code path: validate_and_generate_test_question.py inputs: - connection: azure_open_ai_connection + connection: azure_openai_connection conditional_prompt: ${conditional_prompt.output} model: gpt-35-turbo reasoning_prompt: ${reasoning_prompt.output} @@ -126,7 +124,7 @@ nodes: type: code path: validate_and_generate_context.py inputs: - connection: azure_open_ai_connection + connection: azure_openai_connection generate_context_prompt: ${generate_context_prompt.output} model: gpt-35-turbo question_info: ${validate_and_generate_test_question.output} diff --git a/examples/test_data_gen/construct_test_data_flow/utils.py b/examples/test_data_gen/construct_test_data_flow/utils.py index 0d99389ba58..d3c65d89836 100644 --- a/examples/test_data_gen/construct_test_data_flow/utils.py +++ b/examples/test_data_gen/construct_test_data_flow/utils.py @@ -46,10 +46,10 @@ def get_question_type(testset_distribution) -> str: def is_valid_question(connection, model, prompt): - is_valid = json.loads(llm_call(connection, model, prompt))["verdict"] != "No" - if not is_valid: + if not llm_call(connection, model, prompt): print("Invalid question.") - return is_valid + + return True def validate_distribution(simple_ratio, reasoning_ratio, conditional_ratio): diff --git a/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 index 7e4804a1606..e732dcad982 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_context_prompt.jinja2 @@ -1,5 +1,7 @@ system: -Checks if the context is has information worthy of framing a question, return true or false. +Evaluate the provided context and return only true or false based on the following criteria: +1. Award a high score to context that thoroughly delves into and explains concepts. +2. Assign a lower score to context that contains excessive references, acknowledgments, external links, personal information, or other non-essential elements. user: context: {{context}} \ No newline at end of file diff --git a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 index e341b81794e..4a9eb6ce65c 100644 --- a/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 +++ b/examples/test_data_gen/construct_test_data_flow/validate_question_prompt.jinja2 @@ -1,7 +1,5 @@ system: -Determine if the given question can be clearly understood even when presented without any additional context. Specify reason and verdict is a valid json format. +Determine if the given question can be clearly understood even when presented without any additional context. Only return true or false. user: -question: What is the keyword that best describes the paper's focus in natural language understanding tasks? -{"reason":"The specific paper being referred to is not mentioned in the question.", "verdict": "No"} question:{{question}} \ No newline at end of file From 405de77fe3aa9dde7f8eb9bc18acaa7161544293 Mon Sep 17 00:00:00 2001 From: yalu4 Date: Thu, 18 Jan 2024 14:44:53 +0800 Subject: [PATCH 012/112] update --- docs/how-to-guides/construct-test-data.md | 66 +++++++----------- .../temp-to-delete/to_consider_doc_split.png | Bin 112092 -> 0 bytes .../test_data_gen_local/config.ini | 1 + .../constants.py} | 0 .../test_data_gen_local/doc_split.py | 5 +- .../test_data_gen_local/run_test_data_gen.py | 34 +++++---- .../test_data_gen_pipeline/components.py | 13 ++-- .../test_data_gen_pipeline/config.ini | 5 +- .../test_data_gen_pipeline/constants.py | 2 + .../run_test_data_gen_pipeline.py | 17 ++--- 10 files changed, 65 insertions(+), 78 deletions(-) delete mode 100644 docs/how-to-guides/temp-to-delete/to_consider_doc_split.png rename examples/test_data_gen/{contants.py => test_data_gen_local/constants.py} (100%) create mode 100644 examples/test_data_gen/test_data_gen_pipeline/constants.py diff --git a/docs/how-to-guides/construct-test-data.md b/docs/how-to-guides/construct-test-data.md index 7c012d48042..c985fc611af 100644 --- a/docs/how-to-guides/construct-test-data.md +++ b/docs/how-to-guides/construct-test-data.md @@ -1,5 +1,10 @@ # How to construct test data based on documents - +This guide will help to construct test data based on the provided documents. +The test data construction process contains three steps: +- Split documents to smaller trunks. +- Based on each document trunk generate a test data containing `question`, `answer`, `context` and `question_type`. +By `question_type`, the given flow sample would evolve the simple question into more diverse question types like reasoning and conditional. +- Collect all the test data and remove empty values. ## Data preprocess ### Local @@ -10,8 +15,19 @@ pip install -r requirements.txt ``` #### Get started +- Enter [construct_test_data_flow folder](examples\test_data_gen\construct_test_data_flow) to tune your prompt in order to customize your own test data gen logic. +> [!Note] This step can be skipped if you just want to have a try. + +- Enter [test_data_gen_local folder](examples\test_data_gen\test_data_gen_local) + - Update configs in `configs.ini` + - After configuration, run below command to gen test data set. + ```bash + python run_test_data_gen.py + ``` + - The generated test data would be a data jsonl file with path you configured in `config.ini` ### Cloud +If you want to deal with large test data, you can leverage PRS to run flow in pipeline. #### Prerequisites Enter `test_data_gen_pipeline` folder, run below command to install required packages. ```bash @@ -19,44 +35,10 @@ pip install -r requirements.txt ``` #### Get started -- Fill in the config values in `config.in` - -## Appendix -Run doc_split script. -Interface: -- documents folder path -- output file path -- chunk_size -- ?? do we need to provide test size? How to combine with the flow? How to instruct users to set their own chunk size? - -?? what if the documents folder is in azure blob folder? Or any other possibility? -![Consider](./temp-to-delete/to_consider_doc_split.png) - - -In this sample script, the `SimpleDirectoryReader` of llamaindex is used to split the documents into smaller granularity. For more supported file types, please check [here](https://docs.llamaindex.ai/en/stable/module_guides/loading/simpledirectoryreader.html). -more file readers: ?? - - -Locally run doc_split script. Then upload the generated doc nodes jsonl file to portal as a data asset. --> In this way, we should at least consider how user can do both process in local and cloud. -local: read folder from remote site, then upload to cloud. -portal: process and split directly in portal. - -## Build your test data generation flow -Interface: -- question type -- test distribution -- document chunk -- llm connection - - -## Deal with big data -Use pipeline to run test data gen. Run sample script to submit your pipeline. - -## Use generated test data in flow/experiment -For local extension, we will provide a data.jsonl file. -For portal, the generated test data needs to be registered as a data asset in order to be used in experiment. -### Local story in flow -### Protal story in flow -### Local story in experiment -### Protal story in experiment \ No newline at end of file +- Enter [test_data_gen_pipeline folder](examples\test_data_gen\test_data_gen_pipeline) + - Update configs in `configs.ini` + - After configuration, run below command to gen test data set. + ```bash + python run_test_data_gen_pipeline.py + ``` + - The generated test data would be a data asset which you can find by the last node output. You can register that data asset as a registered data asset for later use. \ No newline at end of file diff --git a/docs/how-to-guides/temp-to-delete/to_consider_doc_split.png b/docs/how-to-guides/temp-to-delete/to_consider_doc_split.png deleted file mode 100644 index 5b85f4200c642475cc6c50054c2ca00c48aa0f8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112092 zcmY(KcRbr|_s84YU87b@ts1FP+M;H~c9&YW)mBUGsy$=xNLz~5reag2v^8Rc*lAI- zb_tS5?GZC1A&6i4Jiq7n+`m7>D4KV9>= z0_EncUtQZVcE^tsx5uVz`LD13ei^&6EBnjy>*@n#-}d(QY8Y$;^ejR^ZeBxl9iv}f zkSXb3^S?KWx%7eSS3ovKc}CUBH-DPGR>WCB#r*kfn63VQKk?*O#M+kN(;*HO>mRl0 z%g_2R^1p$5-c9(w;aV|uFhqFwx8lPYP=Q(A+gpzW~v4>2Yn3%mqY?I%jO+-X1 zj<#|h$DwrSIMD(_$H@dx)9O@EYgQ|;)k4uL803XnXe1r93W~v7$!+_BKC2<^U0b#L zPUNCsum$mLPil$I|2>V=YEHRDGZUwHOR}F}b&2EGu~%I;0xN4?oA8L7uX z0w)Kz-%P@qwt*2R_Np6#76u4h^IV~wg|fh*lJxok*&_Mac2%{fnH};Ay#1cf4BNf8 z_~lln9*m9YKXdS5xn{VlqwBe+M%`4@PyR+y0}xACwGV)SLMzgX0=BlieQfkv`EgUL zv$Nq6{Ktx@JuC7Z zHLD$;MFilv$@L#AuxC`_PQ_=a_Wv7v8$7B#VlfGI8e+9cEIzcBYMhbnju6p^a$B|{ zV<;Bwbmi?;SfV)zL^`l&)IfE$YI(O;BM7Z91h$zP46ODCOIKLmMkQCAz>plSCx^kn z4u7>Mo7Oy;YTRl6F>XtvaR+dGknm4qijB##5AXM$-qoF)ksGEt*Qo z)tmg2toKeNLX|OJ0g4Ng*UU$h5Df&RoecndT3uc>0x9}96x6im-R{F72j8=Lcmqd@ z0#*}R3lt0*IY5}EV6r&m;11Apq`&}v=^ys}yf1WlIg24*YEk^~iPVahf%W9`;VX;~ zx?WS{VaxFm=NW1q`_TMXAD6PS-I$w^3)4e1xK@NT{&IU$Aaybv z!L<6u71eA3^a&Q+0{cYvDj~G>;v!INf<6m>uJ$wwq2_R_;Su4OSSjnUj@+ykIK1m3cn|4V0u=cudkP*sv4K3HA5nPAGp8O^7l!9 zhPcJZPrV8vKLR!HGz)j%E=S67 z4p=HZm;~<_m_QFPJJcP+%m6yJD<~9x7Hf_O!n>eaKbHIZ{EBW;SGTs+J9Z%t3x?Yu z(F5Rs~rW(@AC9+a7)A8WYpDI02f0sUeeu2G0!WreCs50^$&AP5-*r`5Ciwqi+q| zfX*_WUmC`;d;=!|Yx)oj=5RQgse?AZcF))`l&*rsvRpzvk>rnAX2DCm8w+%)t3lNH z7EEg2G_~oGk*q{W3R-oLB`p`K+ex|J8|Yv8wu3JIR?1ohW$SZGHU5$FF`SrzObP7e z0CqB}MwqVdsnGo0XGgV`QTg%&FKMw#1_E=?u#1BY^4Ii8Xjoca=+Xs;nHjCHbVmG} zp+F`HC~Uec`Pw^9!sctKM1Xeo$B`aT>m5UCP301BoRX}|IN0OTa+j}*q>Xt1a;Juchq7)Ce%ylV4{xI4bdd+2>sZ+U7t zH!Xv*I&#d>Qh)ult!6Hr@aD~;WrvQ8Et-3fd(g)nC}BE2Ez~PIp47{J^ARbvW+=mT zjQV2Ajs-eml z4Ud?`Wx?qNhrDZBGDFiH3xP^J8`rxxa-`bs7-_O-gP2VWR0J-H z7LBcPEl<@_8T?<@eJ5s`kGx>v=3c#wzK1%solHGnH!gT*j<_Adu4MfM=lQ1Kwt)$E zs1MfD2M?91F83e$8uBC@1FdS$45;*&*%)a~l5XKL^zqefIbhh1%d){!$*i~lRiDt7 zbe9xQoYm}`D zLr?rdHa^??BPm43?d==nrXc)OOB^8l)76bOhhb%>WOiIc5jc{8Rlq)SF9ef*Bc%N5 zpRx6U>yMBJ$%nlH0g3pHaCDQ*Kn0BYawKcFewY&5y0YOJS#s?Mbn7yyc`*fMM^x-q zb)44%Mv%M!ao*ntxVB&O*nR5Zy(UQ~hYQCqbnDV%Gw)sC+iAnQYV3SA3kkNcC4vFm zgAoIt%bQfUo3L>=UPk6AdVk5BU&=7`LtumRGy$CD;O(&0=Hu;F*j1HLeN*KlQDDgS zWsUqK+-hNfiIh72nbgVQ$k|8DJDuYnQ(6o%#E$UE>cKB}B3p&l2)&Z>-%UE%?pDoR zGmcZ^d$ztjAFvv3dvd}<2Gx6IDd;CC804vynG{&D3Vt%YmI$v+YZ6Ixa2IyYmUWCZ z9kH9gNADzD1z(PHZ;Z~@@sdt>u-Zo+jb;zWe#rQapiU1ChFMqtt?Uje3n2*v7<2fk zr%ja(n*gBBt2+7_>hyV~$y6%9XU|Z*zsoB-(sjE%<ajDX~#g3 zS6k@dd}ZgaaK+8FlfPSa5IW;GpO+I!+B!D_ke3JFR>d^Z9FZ$sajrD&hT&N4xA)$` zA)tds<`fOWr{gXF^%wc;7txh&cu=25ggeRpK0|B+lb6d;hG|Qfp5XcpSU*GY6V zjR7hW`^<({RIuUhvvFZ{5uX?ap}+?>+6@|F2VznKfBpJ9I$8CPg|QlAp+iE}+3Z%` z;GM~m^PO_3y>=1cQ6NF|COd0R+jMGCQ{Ux5Lv80jvguI}B7DNbAFw+{*VblUmf8l- zkr^`(YW=kp@D8n_cy(jLwTQS3Tp1}s8Z%_|Y|b$J9M>JT4Z%)k39gM=dU&V|R?wmq z_jj*UH4Oz%=o#zJ8#@E9J|-1p8nm*wH=6w<)iDN{faTp@drQX<9-63lOsGa|yrjen zYtTL8EmCvS8+8-pN-HRrEDc+C&N@;{TrGqQ?8Y3xyTAc`>5~+r4c1i0;e2gRPIE?Y zNofDLp@+S}(#+jwhAyUkoGA$RYjle**JqvTJ4OV==MQUsH7!QA=@NcszcaF%(e9%i zD_M@JHZ4;%PNOHKk4M1Up~&0cX8!~Npr#MomnNOZsILPjdOm(oF~*yvU-Otaa}adUTf2f?agbY@ac@6;aJh3&5g#RD zV7}ncx)Og&e&w##Wy`mTtn@?;aEiJIn7@M2y$edeh)U#>_Y8B+tgk#3cTnu_nZ8Fc zKl_HBo)yRFL2D;f4m1x@>`60k+!WriQ9c-0! z?`Jt!9vL4sH|DfF`@_@P$gchFMM8k1Nu2I1>53F%G@ zr(d5tPswMU1(0tSq63{w$39tGPw{1ltIk_0D$$NSqHhnFUqr4Idm$(OP9=^TBJtt} zmKlYTv07&bIn%<84lO+{<6^mePJD(Vg~I5;?05HRwv-A>qgG1(iBbcltrth;BA7_EfvL>%?|W-N7Z<2E6|(Z&5NCgwWzj9+i27Oz()dI zuCADMNHGi ztRxF!W8bzTJKUqu2QG*R&;7j2Eh+Mpb>^uxs9CBlx!Yd*%jOZ4879BChpDngG$mm{ z<^iUzPX(lS*#_aeqqR0~qz>$Wf6#NWr!Kkn#yEyb4%M}J%Y&{*B!_tn5XMUR%SI(G z26~0kTkEJja}JAhmkbT@&fzmW&|)uhXzBY~)%)xB{;v&Qiqj40*NIa%m%hnqj>ky4 zGOMg_58KO4U5p(krO#&E1Jmq-3v%;Ue`j%A6h=BLu}Dm2@4Zi0i`E$@+ADptyVkLD z-^*8&B&a(UUOz4KUp=D-{hoBh&Y?>%ftt1=i$BvT9pT3$$@T}qo%?-XL;~~l9;#NA z13VO$UUSl)T4C#)+d0N>zwJv0Dt2dgy;4j(9giJ56*;5E7ww2C=V!Q;o${Plt`*Lg z3^T!&DqGcW#VKF#{=nxnx&M+uXbCS~#cq0=r?;51QU6TNrj0u5X-8^oY~0B4n(b+5 zB_;a}Hz1k|3#EMap+4l56$@K(nFY3o71nHFZ@n12u@j;i9N1KFwsyJ=iQKE$c07jk zovz>6@k2uP!pO%sSa8MJZej$b`N?+32zB_Bl#}Um^o461Xet$ATD?I28$tM-N&DBy zl=}X$E2h4pC|J7f@YrK}oh7g2f=KsYFZi#|ee$u|jm8ctVP^w-YWo-?G57y69yxqLLX zY?f^f+FRJ*TZK%lk2hN~@N|?6=oRay=$f=!&D!uxX6dpG;`>b9HMZ{cG7oVRHRazIcBK4jkgl!W&8$NwZ@bX;ffc>M6*wXr z^mwU(gWv@{<+)%h11R_L+nBA8lcnt`lE=6HX!L*q{8)oJ@kT?Ttl}dpbrj!?#7ya8 zFSvY(+nJm|sJNjs+t{4OFQ;!a>8rl$`7(12dv71$xKSv?B=Jad{|BT!^UqK&w|ss? z1FF3{#Iljp{JC{=Bbd6V84PK`1DccHZ25TZa3eA`C9u|Dbw(Zo>*eY8bwzS;D-h8( zujoDVtI=!r*WB!3F8W{vzdbZ0a^Tp+3()N&=t3p@w157%*pra(a%S9HEq{JOK@E(F ze{I;{O^|UOc$aGv1Av^YBK97OXad$s77=(?^Q&4j#Jx>A+a;Z7Rm$4YIHt}`ctX=8w>e*BgL4=$|135#MCDs zo%bST!|8VTzvh+)vryw76X#X4>RpBiEy9T>X>?(Puff@o{z24OXMW2_)m%J6*BxxCB35EN8 zt~AMD#HXPomC7L3r8E{SolXp2wbVy-&k6-`Pw3->@UOv29pXa{TIn0{9gGDZ(ATfj zPJ~m0o$7adp3WvEBbN9E2FwEmw1z{YCK=u99&CRID7@5JRh65Oc0kKLU;l0OT>xa0 z=X^Fa_3~cP#N1rr461Z!tZuWMF;SR|k>AbwFsiH~kB-q@)wNX2nv643jF9;rw()AR zehQfCLOb|;3L|D(VEFmxd>3bXk5rNbCEeMw$lFhES=grpoLms@Xc|YYHhN(f!f&Ie z3K2FVv;@4wu`ObG(gGs^LoQH`!?Ey!@|F;bjj#dL;7H8W+m?Oihks=0L_Zel=pXv1GxJm}P zMs0bb)qZ*0P`l)isn6G2slS?;WgpD1*f!sjQuJU(1=Hk5H_T0H{Bk3(Bjy-lLqK9j z&cL71v$$22rZTX=`D#SblUsBZkCQ2V-+U+$xMf9iLg<+)1v3m$m<%$Sn^CVJ+#;vg zYQnmA0=C*-{WNcG|y13^I_Dr!13qQT-$-FM!3_~f?Uv2ZL+@&2QOb13vLa|^Ej%1|fb-%bCo^rQP$!C7+*{Ay zL=exaLq;?rQ_yWb&BtpDWvz77Kmf29+=ky-4^X$pT|LC>WP(RlXb~%q|D*UO7-HF3-ug3<45R9)832r)*_x&c}|QyiFB&CULvh zPnl^@#*wa7b78V!HwYrz66$^$PVV7{wFaBlz*&Q9t^~n1H3Q1f^Mafhs1!dII+sK> zRVRCaCmM+4=DDFfTWb&uy^d9Fev_$W7L1)~4}sk60e4=cw0zD8 z@m050Y@Vx9uSU2gL{#{nn%mv-z*jAOUBMhOEn;JsytmbNX1;+#cXFsU+~Gn0C4k!W zCQy_;WGJaf<{R?*&xbRcnZoEFdz~)5mv+wfTr~qiP8U|G4MH8?#!+azN>9kHu?-?@ z(1qMwa@J|Qx#P=k7d5nnX^vKXMvB9v@0@+z+Ml<@-Z`eal6#s2u}LAg?I`l`bv*n;|&30Eka&t7B@A0M6ZyBTm*6RTb=s(xB0Z#+Kiw z=OQYs6^o;up82<1OSp$90o^f9Qob$J)gk#UZ>vs{9OdzJk0_WRG-DALrvkyU>`~E-l)HJW&HQ}ZXJm^)T zzS~FRoMc!3UUOnf5uW1@J^`HVNg#qx1FBnF(d~8H&WP~IdY@&p3atEy#!h&nQ6R$) zwZ1I{cLws;lCy1<+1}=mj{SC@ji2P!l*mwN@>q^)^R0|4%ccs*hGtwHpt-8*wJ;kFze<4)G@bJbK%}Q!P#7d4h zW;V#v#u|hS0IU1N{Y|CS68J1y=V6jFLi{ttc76q~@$RV1s@R}uPBdE`(V{u$2|ztm zwvaB_hOwRQQt;RrS4e&M<7DSSp#Z%R)qx#7j(2hXTrV}{gT~*8w;XS`Bf?!|Jf|xC zigF==9-$BQSL=JFc>P+gUNq_j9PLtHZ`>FW8xwB1Uq1BeBz44#AuKIIbdq1u&7YNF z$jhQ6sY$Kt3D3`a=IA~Vn0Jz5Cqcnc&7&czCzr}!Z0YDJ?-rzq+oZla;DvQoJyd_5 zXDP?_{ps`%zmgnx=ZB5Ppb_wk8L2G|5Y@bUZd8OKkQB4{Q={zud0~+?XI^(BOrdk)|%{$;7tE+0iA$NSww(aA8Y5KEEkCkI?bi=R`Hw z*E*u7HF>xI3pgvM!@MjyfukLJsI1DC@12vOX>OJEE?Ya>P5XC{0IBzy2k{ySGTyTa z&ti6_jU+Q6m zC6B~;2LRw*wMsp*&u~SFrmTZsxPo_KMKJw0QI~U(jAAY z+Zz>-(Fgnj$$qAbJ=5>?(W1jcz_Y5>y|TQ>*78%($h&sPz}4ff8W&;)aqie_B)L27 z92*yPW+xQjqsuGA0Vv;_y9HSyQA`1T$B~De+apx;S?}qQef}of*-sv9S`kId`8Z#7 zEmboFqSlUK0M+vbNm#|W-5pUs%SVF|*a|(7l*tN<2)$8XRdbqM#@B7qq~PlM`g;Ei z;&Wo+B@yQOA@_;79kN#ZO8T;zf&Yi@Rb6H&Klra48{bXWf59pq6D5aHf=OH4JYlR& z{8wY(2z00YV4Ol@Y7R=)IpVL1CEX3_wsL92?D+#q{_53M4M{yoGa3=I53K*(+Im%v zcl;h?Z7;q#j{P>8Ld1I>K^7L{rUtG^uP>_2LyHPhYVneDDLyT=R|$&67%#u(g*HZ0 zg1JcaOw4jCjnH{47v~qNIUHSs-u=lO=KsTGUd$D$@ol`_wVxwos{zF_0EBG{*LnwH zaZgzJu9;F_mlv&cE&9{>rLpogL*-smjIO^^9~yocS_W=EsrGhhebp8|m@(4l$$1HSqq1I-Z{Skdh%WWndX{^N4SyLI6n*fA zxh~#t=J`<wnU$02nTk&>+A&?l7^-v*-Q0 zw^U-3+#PTGwlDK+0Mea|ODd@uWj%p*p*QiHj zTOZjO4Jz<$lz66Pk)lu&jxwIvq<#P{B*s_DU2ZNWEXG+_aKL-MIQeU!pnYE8oYO_` z)`$r)fRA5Ve+|W`von3;Rfq5$hV`Dh-b+PzBl_`S{6w0tH^vxmEj(2*^RfT0cE763 zu3_sFh4yoDPupa?W!h`M&)Zm}%*7Ub4NG5fVlrUn?>EVYDp~QW@!%+qK*t^yS`4YuM-SnzVW!4490yU=?IUu6+OsnOQRvjsAl0jVzDlYf|_ZYYLLK(7s2y@_|m) zErIUdOk1+O0%py@yGc#oIFtrrg$$%^V#ygrCmF3YuoHQeK`^rBH!q{VEAuOR-?f04 zl$&o>Zc-K7!MZp6v}tsxP#xXtSV9M$f6ennmVRmYi|Rnsw(@Gz;2mTex5f=&m_ntR z4dSF<9NSis99W(o{?;^sfDJ}_YuHIvOoq8>2j&K_(HPIzSry_AiQv4>S@Y0~xZ50n z?H4avh@vJOw@YQ!qNf#8LEqnU&BeZtKN*Bd?K>k*v{U(JQq%DJP=g+lA`Pr{G8B7F6`EIt4-DnVzqjZtGr`WVzjY6f{%8mY$`CUqpxz(H2}R001nqV&rm%aM z;isyC*fkFx+*N3|E1ul?a=BH486`?I)^WP|$GX=SIB0?^NcVW5?IB!U%N)X!;mp2S zPdToP%0e+dUHFQ~w1V z*}z=$2H`Q+7o9lVN%`jXeYSy;FPlvCJs-K2vl~h{K730W`g!a02kxv(Dk@APESoiT z=SMray5~pi$%+6$783AR4)SCfSsm+ya!os_WGx?ZSnwTZIv&0r2KT_|M=M$Gqf6!F zHMDayltmj6H0P-4_^JQpw|l%*o22BG=)hwinZ`a?AwkfK z%Ge3$1?<2KRg3PcJKE|$vK81JOEDkl7#jg5RWr1-ZR*(LK1AwJ4&Z*k3ees5GVIy; zfT-$*y^ltKR8;UpPlP#>;upkxCpGs0pYFs4R5&7tv8#OIn^M*IjN_lY+8niMqc>A% zSoDlFCg4Zd`}$IO5dgljZo0-n`}+$9C_|LnROMqwr#BMoS235yciGg|u0ehT1*`~c z2!WR#LQXPaQ4LV@ru$QYe_2h{PSm(BIWrOU!xd`aa{FJHE*1IrjLI}qKZWgoam_FK z^EZ;BhNQJD_N?@Yq>UwgckohkyI+)#rHAGiyO1;J5v zfCCgtJFPCRyYXct%l+wdSJE^kBSb`J_>Vp$)GV^y3nAHF%@~^Hl#^20ZnEN~V}MyY ze~UQky~FEPZ(}<1L&))ydo(HJE zH#aG9i->_!@4S(WcrRdi3bsSygC6GWMxI4jP?*Xmb%e@LyFDpteFyiwLjcA|NNiTJfK+>R&4aK%| zCZ2!RizAF?aLyE9M(f&Bt;n898I3Rjn|`{DTaNmdXDpNSbF=J%EsasnPBm7I3e`G6 za9=ve_#68JMYB?keL}*qF5{|<4rMrez)3;Qr}SQaos>O8&rBywugre>{4Ew*c4sx_V_m@YK)_f-Ltbj&t7j7>^0|PtO}TTTgwKP zsYZ7R3~1$Km%sa1s3BPAB@Pn$!=XKEi;ghsGaHICYG>stuJ4YDi$HJqbtj6({v3N% zD|?NTy+zid;hNf$AM_sd z{MP=ldK!^m(o3Vw??t=3x*wM!Nh%elR}T(m3%qGi+V35Npvj&;T5dDr^bC%5FCP8c z(}9&8(?qT9k=4mC^`%VpVNUclpWHifkD|sMzlwqf6C#VkH$tLSwk2;eMO0=&k&-%v%RGN{OV1pTj@tPE6uX+D zM(BJ0CQ4|DpA0$aDO}(;y{Q_^f+81=x{s0UAD{W*dO(4_4F=(rJcJp?6m^b?+h*0* zQ}xpP>K>-H{&@PEHodRHLe8Yys^W;xOi^P`+8(#xgbNG(@C`_}DAFMe)~k2cQ-)pM z-Fnj&IdLsf$uFXtyN0Q=e&s6hpx-?#HgQtpTFQ0eo;J-xnKkE_| z1+pD)q5|LgyB2ao8S9MyR)3lVE!vdtx~(F%wKi^&vLj858tX-uX*j! zXp$I)x6)k{*S^Go6i5yz^)`Ky9{5bqr{bC^6ei3p8lk2M*f-NcSQ%;pQayKpwsOP{&xI}WK0D%cKzkC zUb9qZ`Cb}ov9OLf=qlH=6rFrnkDh#hwta;ADaogwP%Z>zBYiW=2=Ck28F+E>PPz&i zR~f~VZ6i~=;LZtybG?qt5F1Plo_Of8sh{_vAy;k-`H8yN!Rp)X?+q2oGsyAhdabbE z)2}O>QWx+ZeyDxkbdX*BU@+~^xsCE;P`aPgsmwAT26mMn zxMC)X6J=bStvvF!il{`GnhXX+tkc!qd;|~{a2+y`RJS{2Tz0LWyhwa8R08R%khmsI zSjvRh-I6Q+d-g~z_wLkI^QxU4M2Y$7(YKAVy7!Cb2kUEhJ%u=;s}o4)lZMN4ixKnP z`M2CnGTV0322xe5c)w=9n|(i2xTxUxtL#psCacJj`txXfCwXlBL8vsSCou=j>&wFF zm?yxQ)gSio>G1au=5#Sspcik;a>}bF?U#Iav}2lDG2} zI6ptcBo~_uZEH!uzw*@>|K70H1)ZD;B5LV%CTZfH^Im-WPCbUQ{Q0dE{$ru{Eda~M zlRgt`M%?jGG>L0Uc)9!N{Ip^;OR5mCVd&LC_OhQh|p8OF$=*j60Hmi4f zRu|u)&z~ydsbk1(d1`A(_*Xa&ch!ooBK)Zl<*LG*mmjl3&Y&fTu0~d;yv2f6Dve&D zH}5slRxX|z_EumPfUGqL%r4dIIX5oiO<~T6RwB+C%=je=2@+4x*Y-Te(-s6_gJ#`hqN1GjL*-V17U<~4U*MSQWq0hij#p)VuwljnpL z8B4J1nA%2hnuaPUD(|Pz(II}P=nRYn6G*cRSA=02T1vxt8L4*Djrf-boy}r|nlBkB zeZs~?>)N`}s9=nr-kIuFBuCX%{3yUtS+SELX6vrt(n54wn2Jc-Z|^hCixYiV#_krV zky(aF8@_2*`6wQ$Y_$ol-L065Jbrl(4Si7S`o=1k0hnwm?td@_f{>%}!zy@w4famU zf$!bj9kOW`3a$YfFTx}?49dLP9KBHWGaRb&Ue@NidRM|l_rlW=uNQ-Ug!`w26fWDZ zy|2`R>LMbK2)T(Y{`1HA^vm=37SI??({Vfn}&Z2M|VwtKA2R2svkL2DRM942Z zG#M~fuA;MlZ2QHqxzpn93*U|AO@A}SW9IQ*lK~}7YixC{B`D1MdKJh6%3>6geRG;9 zVNv~Q#+7CTt#V65vgK(t_}rzi_>hymA~K95I^$qNUdwduG4hwR75jSdrj#oK82lq& zc>=-S`6lj%!FqQLG5vA51OF{bxONV$;OA^l>09=5+>ZXZ2<*&nu7mTLfA^xHsT#(iOkm4Sjut+IM^EJ$bB^Dc6#=s zyJKQl{Nc`1o^*2_C51ypy|up1YBxw&*d?S}Q6X@l1#jHl^#Yvo2{1$JaZry>rH&f}Q>w;qOB#QNHQvL7tk(-!L0U|!h8MX8kkA~G8 zi&ghM?JJbS?@&mHw))#cdm`yX#YbT)>rZ@6Vwik75BI7|O1f0zr+xElUL(Ef(ENLQ z`i_B+0gM0bZ0OE@fwF(v&Y{9QOz8nGJM{}2fJ)Lv!{o*VZ-xE00pt1fvyW`Bq21gE z@^!72i=_0Zj0L`>+8@2h5s~X2qaaj6q$$N|&$3Fx(Ed{232xR~NdY6o!-&eNUZYA4={8p}#_<`mli9S%N zh#!LLJ2#PW06R##>hUIsf-{I&PJty^*1IGf|2!!~ByrQ_wl8`$5 zv~Dl^da&}lpgdG^56ASC#>pQV-`t#MiLY3bN;R}tG^>1erqA>=+8_(MylDLmoL=}D zN}vCZJQTWxw30=7+?{VyF<<5T$sF)=%Rx=LQ~#6e#`97PF!4_-?-CL3#LGu46(z6l zy-a>yDd#yw-A-2BAsp9rqk0Nv;O-L`QxLKXOsMHP*(2$eG|Jo1k$5Bomx8#O#Z3!s z)H8!#;lvP;0&E6x9j@L&Erq#M(9 zdbdowGf`pYnn8!$)2IYc^T)EHra8&vWzH-q!;Ts|rik^A#L3iePlXH`Im^C5%d8iq zl}Pe-MQf7>FV)Ny8x_=ZSR6vlXS9CMOKEQK7CcJcwHho*^S^52x?V3V@l+^SquO*K zE!a&pSV}Z=W}Ib94(8+7-b)xOOB*`iUKw-=6BcjLat)pf^jh|S{}47fx@RLaVay?B z??$)8Q+C-NuraY9?m+aJ_nS%6WExL7=65`$5briW$9`Wn$zW!z5A{3J!dmmn2_JV( znC`DCi?L=TDXpdL*G8Ie!}r9x16_{F*Y6n7@h#NFuGSrNf(Gu-8u(i_4@~PpE4jH5 zpAU0uh8>>^76*uY-hQDJtnp6#bEIF`O&F~f{OCsJ@_KoZ(9b#H4vn7>bIYs6g~~=o zPkX&A{W;C=1G?qWa8F~61<|AgVW^%G`!C99)PmgiWyXoSVejLmV&3=4R4EmedeVx7 zzV!D)&2i>J%qbIW_|9uSkC1#Du~HSo!j=3I(I3BI8sblieNsi-^Dp+_2JCIAncH z;)Z6XyuOk2(vp~W-)6Y_xb=%L-BUYmp%v#CXLZDjtmHuAfoJDq!GL;Eg;x4Pa}F)B~ZCHi^xI_NT)y01w)sE;b2rl^xV zA#Dy_u~bgv;dd$?);bL60wRx+?)BR2&!4(Z4*N;D`wC5uXolOJB}jKXRTVQHUlDL9 z&58X8=$S_dT3;LUZZez{o$W(B^BW>_sRMx{ z*{Jwr$$dSx&N)*m_CT_F*`e3K9cX2;Fr>QCXB9~}SvQ5`X7jkm5&z1au2{eJBTov> z<;e{72{ksy`fL1@?=_c(a`Pi!o^oZ`+o=vufFFeup~`PcPxMpvbtN6+zaxAnQu>|b z;?|#tUA-HoeI#{fRZ>twFW-b0$W+aaM=iv)e8A+3BnHG-h70s=4aQF>qR)@B5Z_dB z=(aet|Me+iQ1e|%Q*B$ZkYj2^VPhv~f-Yv+ad4cO;53tE3tH!t9@HQ>HS9i^gDV)V zq$(vUeAc`+B7>{hmW2G8Cal^#)iA`3&ns26TidA8k0%iMSGKefA7 z<(r70)TvFEuV0Uacd0mF=*NH5O{jsLhVCsK%5vidzV_^l#yYCLPc)}_e(#c}pVW^f zMB8&g{^IRTD+z{ORTGJK8Q@R7ml8n!Ws^EA?v`il!u93tZPm!|_AmTMM8n~w_07~&_y?Kf^odoN_xwjWYz1oG=~mj-?`!=pS( zcMralQy^!@tH-FeL#;DIJc@`U5DZUY?UcXI_+iK?kI$}Z45V@%+sVBn-Fr3l@QlrRX2F-j5=CrdDn8P%Gz22^^GfMVlHQ?z-O)^=7UOq zw5LHdT+)8Y4(S6PVzzqRp=P2^G;EN|0JI3(9&~{S7bN(DpyKv6u%D`pX0hR0QZeM( ztpYEn8CsWtN29Avwx0YzzFwM!s2Kd^?@ISoSCvJ~=1e^{U_{d*X$xb~L7B|eAY(zA zkoHNsnvJEC{o#P$3ayoL-K;C$_$(wXoW-C{u<&4%Cyp3hWfgURg+_6#&13#adLu^ZAfb4uP7hk+IW16y2;-ti~BPLcs_3rqAgMuU5a}{UDd=~G}Vc`J! zBnO?ICnAH~bv40I)XungZvLiwt2_9y(IeX>nxY!(lvI(_SETpos0P(`q?<$itPgSP zKIM4dYa2ZC{cPA17c*hr={xWczMX4Z4X>3?3SZrHCfs_26!ueolaf5jwKNkk$6KT~ zjgaHsY{6IC*}YFLGme0GS3^;#DKzSwU!7M)8oaoVSed(o`Iu$9vdBw3F#FH|?;d+4 z`|R9AxhbrW?*;$Qw&5GBh8Z7i8YMl3g#iJ!wzkyB_E8yCRffcO-vE5tCCkA1rF+^c zXRnwsw0KEALd(gDT~<(nCb&q+8@@VmJ4t%sv-XZhiV|)N>?8a%L+;ZBix9XjoKB}( zW}FXGLejLN$47-=5+6XkF;h-qa4w$bPMFjBGsfN}PL&NpAkJt2DletsE7Y3oT>u{! z`zGw}Ei5VliEe}50sllePXN3z^a-M!%ej)1+uPeTL3hF}Cm|ITx8y)@T2CZ-8vb3| zz+)F$d{yr2$E+xnsm$gIeV=L-xF^_*-FZWHC^&ti{IXG&j$3J!%vhbl-StYF<`0TT z6}=txef247mKnctKQ!L6GTO|J=Ny5miZ3&lp>%t;!qKW>6Vg43FSaFjO6%Zn>sn-7 zHTHP3n&!s)HUI;!qORsd|1Ro{GNj9?@0oOY07B;72%%}gS6;Ra!h5eTdgwnq+P~@O z*;l9ttE>AsuRAk1|6VY)Oia%Xwk zPMH4dL!{V?UR%^-$o%o!2U$eYzgLe#u`>I!S^3mtpX5-2G}UBF;%w+}RukBzz+1zn zqG%!}JoTQJ5kf-Q+4d68JP(DY}) zv2$DQe+v!W3=qDEF$>m^&B2uIEv6#B9zNHW8;09L2T^yz${R+eeKv}{ z)Wv2@%uj#PtzRj4e0SD7v?Vrr`S-y=b7lSNyGg^6D`|JjD!qM^Wfsn{y@f{_!-&b~ zBzOqHq;*VJtTSU^{PxD!gCTP94&>vtjiM41`(W{xE#kW#VmA$7Db-K4su1=#eV_ znkIcdE{s&jHD|Q3?m3w19HD()B7%*kU~Rw4F#Q65^G#wEzg~Xd(|x8wTN2Ptoci7{ z{Bod!29_|i{sB&Y-^=I`N5BaQfKNpd%eJCq~B4 zc_}X*zDr==cxcaZ z<#&e{M5xAlz(}=Eq)MuLX;LaIt^8vqL&hHmAZKT;dt>65Bxo~Z7+AkVrpAn3LUYh> zkxR;~%*YRA6M?hxQ7Cho}#a=T-C z{AQhb1O-*8za>_#x&IGmZygp@*S-y_C?JhUmxzE!cZW2R79G+c-3+NW-Q6XUN_R6# z!_YZH_s}^s1MkM)qu$T^9`AR2-^YJ??3vknuWPTp)_I-r#3$Om8fXMHB5?EGS`sf7 zGRhkR?EsT$T7wC7KdCSx55nho+pSxLUt(mm-L*5Yb__=P#G_EcJ>BabphS6v2m?ze zA-C#c-gW=6>r z6?=PrPN4tkf5!Yk7h55erBLj{o1PEA>rNU^bP=a*SzaaEMEU6eTPd!^V@I;2Vve3* z^{P)BgwsD;XbQbLSC08O{xkG}lUN~}*g{E%EsWKcjFxp(ytYjiImLK^JsXvSqC)GP z`C)n~FYz^v>hcP#@m$XjSF8DO4*Teuc$i?Rj2%;n63F))_7@e1<{eN7B461@Ge` zYTyE&ROczm`ICf}y$YOEA_L_b!Z%xo{dxx{>Ki4n}7nhNMrH%4nT%9%=vA*Kr+1W!QfmBvJC2% zDHH-ggD~To!hfL$9K!44G`~G9B+y@D{6F9~68|FV1<}*|%OylA_TO~0uk!x_jnIdm zX|0+6m*Id2mvEZb2|yt%1-H0!3m0itc6y!EJ+OgQbbU8VQQ&e4&w&1cH(rZr4L=no z);nVX|MlMR{%-_|#kJ}R0=^2py!9c_zH-MbMQD(am;N9zfab4J@92Z?mM~CahU&XM zETx^hm5a-9mSZhi%AC9!h*#HnjXCJi9AMdsXyq){XleBV$SW5|2FY%@LF%E~BvEaL zFPP8_3@&I^OgQ}xHNDHdm)$@Y#J>rFHD+3y=9&$N*I?x4WaPOuuu$Gz3S~Pqm?^WJ zs_JnT*;k-;Iqb==1Nx2qnO&qq{@uTM8DQMs`3M{ zRjB5U6j)1oC8#UP{BVg))4`R6`h+5I0DmQu+ad-R3^0slBymOgp9}jP-M-+p+}kt9 zU>j`>jg8IBu5-s+Z1ZE^gc=J=E?RJzBwh>Hd47on-vnyU0LayMGc<9ZNgc0np{*j@ zv0fqP&9RT`cVZb-TqfTmB>2gX9nNOzcVh!76AFEPmxZB6er`kptP>fQcI8XuhAv}TiFY6s6_cuu67NHL?ul6)6Ph4*q7~0M5)nYg_ zA{5dF?(JfAkEjKOgk~A@GnP!a>h0fXfR3I&?E<9l3!_bl3dl!6xz-X%WvA2tfu?-co!sjIfwwLbJ7M_Z8N|If;n8Zm{T>=)0Z-axxX zrPpXP{I&G*$a1peSow}x|Kq!8vTv?7M)MOLK9N{#U=tR()!$s}yEW$uX!1uAprR2p zK-_oG%%Hav^7QlS(s2q|%?q|dwm)}}nKLJXNUdNY>`od((Vg;1PdCbd_tdBZ37I#B z3&%8iT{NP~VFHe8Vbfp-AhW&p#k~22H8EkFpBs2xeBBI|(sGY9H?SWRxd|YK zA{zmU3**5wGpfT>;mfEstHtU(0Y{wU;}6Cg;G&k_Pft*}90WXkxG#x&KF=?5CW_9t zR}{5y96ywGuudB}p;ooamNnrit)7q^!3-;+S1~wl@5m9UzZeMYig{UE! zo)sq;y?~X%M<%Tx*J0`T65T))-@W36zJ+lTQ4Pz<^5nN`fK3Na+2&UVZ1}m0+!UYI z9Zfq$Xd(Odc_#*FTr!QSRMgo;`FlW~?{csw2s?1gPL9$GarMz$Aj)9R>*RnlNe>GF z^ky6~(a1~j{O5=6Ivy^3;S{M@^z0c0|Hj12n@1<~vo5s%7z}--6Fx$`;4@f~;%mun zbADHIa&j^?F)^{mcZu!7`b?B67;A&?UzmC)=l^Sb{Qo|`280doC;F1T{Qoln2jO>^ zUq^)g3)wdp$U18Gj_kl)?)_^T1x^t)V8Mfg&*sOl;k3DK zd5r9I3bFqB-p0-`#(LrI0dINoa!16DtDGnE?^6jXmrXJ9Yew>-VWheigptEfDdR;- zamqE5IxugE)*(u)x3+wydzL7lFYaN~1n$@Vt|*!sT!}zHc6f7E0o60){m32fRhtdPgV0pFJx}`-kPcbW;!d% zWoaU7E)|&Mk+i0&rb}CPj_P5 zBDx~thd_^n-YgmYxp7uL#sbpYu1##q#-DQ>Y13 z5eoVfA(t}oDO*~=1MP>9)_1U_&j_g@LrB_-KQ$Z_O!;)NTtMSVe|gM`s=Oedmbr)H z+uGAF?GbT98~6S-0X(I53Go{s>~{Db#>0SF)qK2`cilA3L;?BxAO?|8(1LK{nv7_7 zuFP9+fADQOqeI1?yYn=h6KE@L8-IQokw7A#@%tX2zm8)zlh2?v>EqYp1s~^~=8bK= zi{_H~{W+4$v1N2dhkgzFG7=tHg+2|3FWsciet#MZ+k}##ZNuC`dhT09!mu9&n%fNb~86^Wxjmi5`BTxl;6}1XCb#E_vMAH93eklq|HLDMeC~gpKp}P&Jj>QOk<@T7=AMm97B|O z=`x_VfT0 zv7<8uRNudR1?5r*=qxgch-Lh;>H0|@Wx#7G1HqRU7gwUfX6;?SZ<`;U{4)WS?O*P8 zf$-LORUt9p5*O=-g8wn{pFg0o!d={psyg~}I8+p!@)=EVL~JjWtU^;QdnnqqTOB2f zd_*MF;E@f#8r0px!_wnx*W{VkYUZD*M2gBf-p89-NclzJ?IbxsIGx%?Hxq`xV_q(T zL&y$)rJ@pPS@`(7!QCAcv?3AA}_U1n1obba(Qx7ODS1azP1%r2b* zWdPh816ySxiMgYU)83zdo`@ityJ8(orA^zD%}JFVY0O!bCJU43G%ihk%EY`BEJYua zX9P6=)`tWZ=^4$wEOeT8tuTm`S5_g0J-|PCs0N!~>*8ul;?K3?Nj|(rzj~CF-El?u zV-LUb>jQ(BlMfQpdE?A~jv@KDFPmh0PhWbw@sojlmES+c1`@bah(y0XW5?0gevM%y zRbzTyjpHid=cm%$m<5T9?u`m-Qq}9v+N^#$f;O}?iv`z-J_7jDLCD~Sy zWZ892OF(-5Ui9JvYH2dbO>_B2?E@VK6w^c_nTM~U|BgZ7Pqxp6Py1~-zN%HVx4wK{ zXZ`1!@!I6qGueF}*scTJkc31a2Go9p{_llTBRm&Mu*-!6{k6B`oIym<); zMovzUe;#s)pv5N;wwD^nh=d!5u*=>+*P<(EN5A$ye770JZ0p|3R@@%HQ~`DOOLt_Z zYK7b1lW%*_5@KgNwr5Uyn!o!6*7(kQdkg1+jbCRZm`jO(UU;q6y15wzCt+?*?{wD{ zoKGhC=Rq}G4@MHxgnMDtN<&`|@p_-$%Jed*YDbm#9QIN+U>!9398 zN9Bv^p|hv9Eu$<*WWr{0Ev)I_!RcYZ!`@owE~VAf+iaW=8krvmtY{&z9# zvY4e04|-Jrd%(1RRX2XlIak;=A$z`SO^#pQt9tllH{M@W>y_(SVm^s+B?Mh#_ zX+CG0MQmyk1bHsU+bkXsW%iXU_1B~EVEwha!pJ*yrGEZd_&i=0sj?wB;I+Fn#N$+?w_nJvVY=MiYWwW7?@SXd zu7k%rlo3uWU~99;3pzBe9c`R@AO8FGA%V`}{(Q$Ab~-xmG|#`f%z8~OzL)M8bJ+=F zsF%!FQ;|ZbU!Qx8-z5+-CH4Ktl3I5w&wVM^tv1}oBeB;aM1Q`3Bs)%fxMG9mw082Q+iQPAe_=1fPGxz&=!6&=@sb9lqv>|vCL{b}}0GT+sh?s4+Qc=v{1DfR(h zo;6Upj^vH2R)5}_?dv%RKCPMdjomV?5{H{D_{|!XhC^-RGXcY zX~U_qSLt*#_p9DVJ*SmfjHf^OX@D@aT$Fw)P>x`4@Hm;4c z{`t@XnAaG5?l|BwGd;a^nzpsEVXw`kJvdQp(?vPIF?ZQ=dVcozwA*^PR7xEP=#`z8 zg#>kEO^k+vti5UE^RhcCVb&VwOsD&s*yGC>Y+@@V&6}CCD+IPK#9+AXY$DsazlXtQ z7vQEzwRv4Ymg|#0J1Z-S$lq;_1>Cpbuj+6qS*+Hqeh!aJPs0J7v`bBsZSP~B^uHHq zH+)}K;hqXm3%hk&GogF)9oF6l58$GR#NCR$v=viuA(`IYK=~lbz)R?GD+f6aF}NbP z0)9HdqCKN5)T}V@cdo`_0!1VoQnz74_m?nty>5gc^K_kx=A*9PFFV>*s@6_i7wEczusPz^&h7UMA{$_XP5! z{*f?B@?US;W6q=y3Aq9OqwC6o2U4!{&8KREL0O;NbG?_{saXd^FH^lytnQ}%;Ef5g zJ_(%E*KbUiHz}bERwe4?nEH_?%5$^6^PMHoCACY=(h>9ot{Qe%QeMw1yn~aR%yQn; zW4kaUiti+XUS^b^Y}$xF-@=cZlAFnk#!oI=R2G63Vb9P%pX;tlon_R4KA0Tq|2F={ z5m;^aJsh<%?Vp;b1g*T@1vCPMK$~=VIr63nfO@r#6&*<+1e&kKe!-E1cT<~}2O6(L z*Fxjvmz?9}+gEyGk@mt_-3@Bos9qhvIbz?&kYtXYd);@46Po(PVgVqB~jo;Li z8n$qzq~*|JZ`iUQ2)lVu2>Ig~rB1l9ko`zwS%vR4^S^tUAZCE*|42{;%Q2%JK5}BvWa`W31$b;BUl1jPRfw%68C`w9qiu5)jk~v3 zyT6eJK&53(4CVZGw+NWcYH$4Rt#0p?B|ws@t`a>skVF$X?~eH_Oq}7Jf?K;)vDDRW zf}Yq?w+d8+Vz5zMR`x*j_`yBTx}A3=1wskx(7 z7ns3-dzMx`bY$e=5qwH%c6L0kRmp*TB>2|gl zc(uoz+$zZWRlfxH_+i?zU}3(hkGn_tu5xcVA?CLldL>yR0gGjZ z=OJ2@S^~_tR)neHM;y#zybuOvYC9`~tc)jdYy-3>WF zG~hsf5+#gow_XU?IJ*x0Cu7t`&OUHU%BFScmCG~Xo(EX8Pj3K+blUroI|^I1~(t+rnY=jH?BOQ(RAoMR@Qiva*H-zLRq2H z)oN5DxAM%ZCjWDV7{vtH0eoz0)sO@lpZOi@Jip#ofnO6j^m>Cz^q#o#96pZF1EAgbA6$ zX}0m4UO9D3@l@Vo8Wc*s$sKT}V`eXj^tUMUH>tR&IcPh?*me+%79s#G~eNycD1k;9iZCI+YJ>0}8dh zwE>Z@M7)lB&B$|Z4I&WGa;_)kGOcS&oZ&Kmc&g%ksIr@4S$bqa>9qfIH>I%j;2hp_ z2avou-fHJA&)IfeJ$CEWZLXpisC;H_g?*kn##*&D#U4Q0^m~@?=$bQu;8w0e;)PRv zz+raavk^pW0%`=y%C7suPESjZgxAXItZuSKk&i_)u4HYYn#d~9D0&O=*&Ius)pecI z3{M{f+K{b@>096U4l&SLfj;z!AZ?mR*Lt#G_Vq0Tyt)kNy60u67;cQnB4vbY7~kgC z0aUdDGA%48yIXj_4L)#e@r(u1KVqSU>{x-}@o72YkQM|2P5OvNp!e&GAX$s_tt@0Z zN99xSSw{lu;e|nb884;HZG`U)BSR*)Tnpe1X?ZTGHH|{=n?PUjwrkPvsTDQgrKx|s zeW%+AfI&|x>_kj*Sl*aE|2pq=I$dfwN#4vtUWHrI_A<>R@YwL;N%5+R=*AkQvvD!y zm&`LB1=B20OA(?OULVFjRM8=Xwj_$9Nx_5d=5{+)&wh)-FC>v#m=Wu;_$Xj01q_}%7X@zB1|Wu zQv%eQz;MkJ9mve*7Qm#E?xl$8+&+&gZSlOg+F?ClA82Wk^k~c@$@HY`i`bFQTq z;c>&+1ob5d^Fk%2=lQ7XoQuV|O|d(hN(eA35>d=uQ36yaTuw@0X0C6ak@ zs|aFm6{4r`C&j{=M+?t-tNNeWouv5w;2j{99>IkOzgdHhX={n;j}2H~@t;5+%$;}4 z{A09N~jyK1zNm{F- z1MmJopsch#Ay7t_Fhs88+W(Nn-H%mMz^x}8dctN)AL&Ql-3-_uUfGt=P{!t?W6`U* zoG7XS8oyyJ(pEvE!A~TcFoYa55a<+xX?8rjZwY47p#$Hku%S`~iKePKqM=aN3~c*s zlSTf%lc_CV(a4;uVA(5XLu51#K}VTr0o#g6#gFi$W>h);!pQzjA83`@AuP8RqD7B67yZoFsq4(MD zvH2)rRYBQVd;MLmc|;aky`JKZF|Dg77OTEiVWfiJyNNE5x=0^*QRBX%11)vD0tjPA z9$(V^c1Sfu+^<3K^Xu8|0y!}Q4T?gslAUdesA8a=@Tcq^$srQc$n1JX++=g!&y|F5@jCl~=P}+IYfl9+vRI4eDK zx~y0#u#@t~4iJBS8QJ5>)iY}G`f|{wrJi3YvAf+u&@q~U>3OHH_ zj$rAR=3{Hxm*9CuZrn;#7K~>srPdm{$>$_G!fH-k6nN5)nR4B3BoMmRk7pi~}G)_bc; zm2ebX;qEOzx@`jza=sb)Sk;J8J<3;4t)D{rUx2!DI&5W{A2F0>_AqgQ;z>P1RMlin z7G)yiDe1Xt@Je3^E{Aa;Io%T`$-Cd@WwOKJwt!51wLFlkm^BmslwABm9;wuf1#QjS zeC_zHt5ZPT1qbhqN`|V-Hp@tU7q{R<`|8ud90#&6#{Ja!t4<-EGBa^plWF0Ge4MD{ zNd_@4cqprdamXw`2>DpUqcb`p-^ zx?B6evm>+Nt)}kecVX) zjeZ4Rc_!cc1Z(?w73Oo|6eDGx0-ZmRuVBw zM;x!a3n!U_v~z&rbA*-W15ejGA`0v{$P}~6mXR4Oj`8i4tCWP90?hlLR4TOuWdHnC zcq!9X;!$s)4ubJS>z{GU*9F;C-n6^6a;dlt#Qrs8dZ9W9p*)DGAyS%@e9&?p^thkP za(gvc?4(`e&N^ngq}uGtaJNPqk4fiicHQg2Y44@T;+=Twqbg!cuACkw{-Jd!Y0Nn9 z@Xhd1#CMprNSyVhiIbF9)yD`WEor!U+$b*mXhfWqJZU@cQOFwhO4~F0*Uk^=saKgAvD|@` z;k951JUb7b;i_jX5zfpkR=b+L4Pqd|6$7#9w=~hy@-;LarMrkeoXc#!)s;=W1Toe& zi|M0MNMdd0#2TYm2=;#mN4Z-)_sf?txGsXqc`U`|g6l*zdKJBBsgGrlFy}?$qe}K^ zE?81`0_a5`OPccp-^T_TN_z2bt#@ElJ!eXY;?igfgW;TMkbKOIye zq7Rj&MxO9J4G~XW?aVc&?8t#}-ByBCO;e_Ka%50S`p_=uBWY;>dhj$+jVa%Lf+%nA z;ckw*QV7^^6@!|uRIhU3;we&5FIhgn4;m|#E%-tqiJDwxD|U0};(--5`IEg0Bw(uy zxZFrs^W0g9j||`Ik76@GBxYVC^xu^Z1a6I9gx7(8nhG)yQXc_{BdgOzx}nJA=GUxS za7fFeSQ!!CjPaIG)n|i6<-{U*^J|0#)QRu;Ko^!yMT}e#WKb4rLy@cfdOevB`g#4a z`PHO{rk;|CpjAdL+?pD#K@vT`ijBnK*BX267AF*q>z)O2)4l&}wIZM?+lz&*bV18ZzxOQJ)540^=@0}1&bdD%mU(R>40 zPK#VWJo=ivU$y=p3Kox;JS7YJ%N6<53rUWN4@Gd)3Qgs&i+=GUO>2`ylN-k0CevR|*#XcZT^Pe_>re5|*%#-;A=`L$g2QFPlG9 zugobn9Nzp3G=&-e+eq$zCw#4#lbYTlIJ+$#d&N{Hl1+e(*o}1!pz!nJ>0I~cd=`(5 z3_>)peH2=cKC`H)FzqKh{dO+fsN#7A?6hG<(%$dH%(SiiPi} zcx5q=>hSV-Yl65Y`+bPC%)mal!UPmFEI%jp;IjFA4eZP}=M;OnvEy22F`D;Y zQi`-iBe_mbefS7Kj|$DmvXf&EhVL(%Wwbd~DYaOHK;o!RY{*-DT9%JKA!mcx*$)H%w5X7pXF%59?;*tWVX^t~D zZ%M062SvZQ*YNAK_0N}jBa?(YcXfPr>*1M4mx~|zQ;27`O2K*}AF+BR>!GZG#nm;1 z#XKPIxIWb|26imt`saSmgS>IEeQKk};)y~4wlov>?d{C%23kbOQs8>MC%RtbwuIBTSJOD}TMT53Wc*mT zTRkZm)Ml$KZvdI&k5G?-Ivb?a2uC0RgQ}lGk{LeNpj!=MZO>o{V`DoJL+hKMLykv4KzmCzQzk`NwtblOMe1a&PA7@#zppjkli!7o?;1JGduZVj1LHZGQ zg*(Fp5Ba$X{^t6v+w*v(ZR~s2(T-b1pgl8l33=;8iSE{E)_`Fhk@lP`7&((BxmE|@ z3pf>oquIHZCYA1-tyj?-xrwM#f%sdDO7w-qo9&0RCGmVk45QL-Qgmdm0K2T#K$tV& zY<0y^-jqYQNf*iWe*(*zgx#=A|?` zOa;thANNvphK|Zr;G-nB9v%uY+iF~wZCe=#mtY?Enr_6%#E6j5+r}t47Uy;m>65oP z>rg|Y@?)9LX_SfUnfuGABtgUPhp*>HURiQ!3jRZGTbGq!T9mDtch(Ta4f|4{*Vc68 zlwzXN-N&&^X+WXvF5@Wz79cj_3^+D+Ahn+YVs8rK`IPyTR1#El0yPCO7Cp6YR3nAu z+bgct^T-QnP}&#ePaaJXkax8QU;b3hPmAp0Zk2>VHj}HEh2yvsBE_2?ba{84$|4jj zj^o~)M5*F-zcwxD+RLd=Gq|WY+E%i)vQHif+Imsb%&!~E(ZVX6IhNSf5PG!ej!CO0 zoQPK}9g*<58%QKkvyl;7;{%elrfqfsjg=<}HekzAdO44pt_S5@$1njJeji3 z_vCJJ2*5xi&$(PI;1*>%FGofWQmKzp;$;#lbQ{{?)H9;t&FjT8qD;Qtb4uc6pLi?l z)SeZ=+Kg!QEn(9t0sgeo2$>QZZ_`F@bQ5k7F|pYX0{jC+87{YcOI%tpZPVTt834Gp z3?!v&wn;qS8dtyh5lFB%1Bj(gXI=GqoW3YRdjNy_ZwboklSn-u4(9029y6vQtJNVO zlVb*8S-#QU4G}TKOknVckZjJ*yv=FZH;U9ob+)0}e>>pn z8|DaHOYP-icg0=u^xrrju30LVSp;q&-=GF~rQWb3*zzYm zI+6Dk{APrjI4dl}Nc$y@Ri71ka{10LoT}?Li&cNNy^tCD;3T?gn^c z$($Lrn8E!B%?@)fOGPXF7MmA>9G9Hlhp|2mfQBJG(sAe~+9V=oB2V(U(9S2j!qc2_ zXDGf`;Kt1_6e$$yCb$01bounH3bJJ4wETO-MOMb)lu3a)qT9_sP5y)=#&pzVE2F6l ze(MHCzZ~~UO!pmw#i1io_4vlZnqEm3??h;QGYcS4R)|Ntd>jI6+rMp#K1OIP{>Pz%0QqFM_b(G;uTZkv9omVds{JuMorJHNG~5h z3Ih?s9X=zGvC)a;dL6R3Z*n&TzG0e3hKgs^mOr8mO)$IKb6SLJ3Zb1xYmdGjcMo&+ zF20Ysr4e6Yzrc<_eZZ}3nS-aC^ZAHd*u&W(QViDCmG66>?8S!2MR)d`0A5Rlp}k!v zh1<}}mc?bPpNo>q@MibM0YU8n0xFym6VOpVpXI6~>PR)`!u=0XAHM#$e-~8bYZNMU zDXeJ2WC_GVQd1Nat(_TENX+F?$1D0lBXYLs3JdWaA?*6@M1xl3vIY8D%#Rj*@1+&3 z&*?Q|^i;CZT19q;M1=MNQAcRv7m9kLdXU-w0kCKf`zjAedNI4ZI>S4QUTK+H0!|?N zHCUh>&M_v?ZuKPE+spW;am5}N`+#r#cOq(13$V0v48x5o;zoK}Q4YEn#bD&uqm`2$ zkW@_5_A}n;iAw2&OObc?X!nRkhRAEy(f5kU*H~o+8DEX~sz?u~vPZi1Q_s;kHMP4p zJs=YX_>`-|1;R4Sm_zg~FcadN>DJMyhvx>E1~&mpN$D&23BCt-+U(N+)Hg}Us7{Nt z0@4|bQidnm>UHoBFEUAt`!>Z!r+7S93-ycRSu7R(n8_J3o9g|{MI5TaBuMVmALN!V zyeoVEl>0@-s~@+SAca)WE<4G7zleY?s_pS?fXIE>Y(UADUdA)Vul&e`QsrHgZ+^mJ zNbuJojwLDawVqg4#OiXbl4u*}C+7eYq2VMAYNx4{j()B6sIseqK)d+YSd(_v&uypf zi((dfq>-FN_g6Se1%@lv|19rOYF;&LHAcC2A+z`4gqY1h@t@E4&?0o(0%ntlGdXqL zVJ7iciFtX!J6z{IFZfI<4mCuJbiU_PeG(>JkhnxKE(_Mca<3^y&%tMXD9r}S*|;ZQ z&FRO=&+GB<8-q&sD}tzRm5v`OKJKSl*6}hn=~W=CF0yuu!=U$7K>YI@J#eyE8*ZKAjf%Df2;Pvk+Zk0>RMFBfL92JN zpt$Hj;mXe196N7qp_g+-_E}g7Hd-E}n>8`&Cs9Sb2HbDGSGu=+3`dM}gvV$~N6q3t z2U4B9!mqI`%!qlC&JB#YDJ-mjT0l#NLouLU!1Pm9aE1XBhE?UuCgwFeb~fgAN_`@J zUkQQUs|Pr}QgC#)(&VV+{U7olGAy=+u(s-2bQHQzYGI+TZ8M_c=(|on1}bqb z34gY%Y)uW`VA!RFZ9lZFlpp0&sg0(4)>Be95TQ*Y#wUuP2A}uaUUBf9N^hGN^i-6Z zii0J5K3-JCf0iG@9iguH8fmhPaMa`t!*2f~NwLDOR>!e$_uhbQZ-*<58_OsD9Ch2q zqQDC0OhRyxa?BHC^u!I^fHU4ApV!-vV2sarBYtwG^&lBrq~n-iv_K?&WAH~>y=P^p z;Lpx-=d^~VO(Vx7;ob=YTEQ0*q@XA|8#G~rp$Ww^fASUICX1tRQ?4;4K?ZFr)G ztMDdRJ{EsnOmj7zXaL!JtA!~2!XVa3tbH7Je(~sQg_)!P43v7 zXnuXArzn1hG{{%6+Y~ZL`s3WX0x!^(r_3rI=V3B)*j@_a`1l;L=`Y;Fc9Jo9gpJah zaeBAxS??G=wBj|p5Qi@LaU2t(RolIr2h`Pb-J>~D?Q}7-0JD?~80X=80^PlpB$9ES zwGGmw;ez)*2{*CXejw+cIJ7EzPETt+cxXImuan^}&Zj6^ru}5+YsAY#-1#mBmN~99 z#-|S1m=qDUtlpQ6lAbfH-uK?ntCSd+#55;JWiUtblnJ4Fd4MSkFh^uFa`u5<`7Go| zd$3!c*-9tx)&r#9@x;d%ME~CIu2MB2ChD;->oBF@eGj^k=S*VmHTf&@W$h`cIpFhw z4sU7yV^WaI*tUDmKi;g67BYWC(x<8R45N#@XG8hNwCi{C*;in0kK(pqW*NuS2dnNr zZw0+vPa|*6mbJwGVLq;bxc3xZCh?1Mj(Bek%cF0EwO@nLrKcGiR%uJNX`1T$MwpPY z(EP`_uRUIjW|GD&!^LjYCj~5GYVAW$0m1(nuc}{#Gc+h7L{)}L?Reoa4)|Q^1~6xC za*;?4g_A??>`96a&71rq8DZL60|l3=b~`t6cg?{8)=3bCoOAs*GX$ z7AyU9Qd`m4CUHi5?fkgwIcGRB6L0G(7W#fxzM?|q8}uA)%jm`H(j(>I?~=_3nnsVK z^Sls0x2pF0OxxM=wyo24fV5lOj6g8&)4Y7T8)t(UpjokE+&K4Tl?T2IPE8+ACi;< zb9E^4PA*DfRV&h26y5)fJC>eb4I1483}F!}THEAgP)Y^6WI2rtMKT~-B&O9~)FI<= zKP6=YG@7U6JLRS+$5zBw!z?R>g`-F>FTKMcKM&HAJ-r z2eSFR&`0iTn6SKHs;0$Jjn-YwqbYf-<)#KXYH9wX2<|_JhjIC7buWK&4bp8m1v9z!WKSLg=|g1{=>-=l_er*8d?OGA9Lys!j~)ZeJUL#OFe@-nQynPxxSR1FMyndh%C* z!8})6AlZrl;Jc+3SwqL<*`LC*3mC}T0eRADBD7jc*}Q4$W_~^&uZOX#qq9Cdx591g zy6&jq{_ayE^LAXJLWj0x&6lH?j4q-D0$jN(dYmeZ1aoq60lft6xS zYx1%*^Xx2(wnd*+azv4J_b*Q0AavW&VdGJBq2i{Yb=#5C*IQnow?x+5c=e-wa@Q&Dz6tz2{$)G;Chl z?9R~El&`9-DUp`8T%g@%u8ws+@J5Mk7{0Td(lfwoviX>AuYi_|VFkD%)krI&&$nvM zTeb?2*<7-jJdBOJYqAMAQ&%^n2^i(s(jwB|<|`JbivfIsTRw|L9Wu&B6V85Ab;MTp z!`XROY|YxL3UBar8RqtKQDw{Gt>?2BwbRy8M~m$b?<7ZDo-h>XnVf0C#ddVS?$7^` zSV^JSy{!V2m$N|lp+2&(9W`1ExB-wp$4aw7sxf*Z3fDBTyyjnP=nUuGPmxp$4UK3SqPS??T!6Ru zOm?KOmI$rPBVg10*{I`3%P$pQG~QDw04BLlppc-;B8=n)OARLIm#b)f^K@@m;KMi|olSPZnLQ<*R_>(+){ebvTLpU0KT zjc0n$dc@IfENE28iJ!T(?O9+OB(fF9xAjd~!*zW>H*rE;a>U?~`9;JL+Z$pTJtD>h~YH5~|XBeOQn;aTfLhPvPK%~-a+(0PN|0AAIczACmQypwi)z z0MEMl52myscC{~g&Bqzz@`k+J(S9nf5xtyMzRf9CN+*({Yh{C@gupmx`tG8Oh=uhg zU_4?Kx-q*%OQ3Cqsag~9Fcd;DY5UwVrr&?E>)byF#?#JeJZ_ud{V?=$Ll{}vQSl}7 zHe;G7gASKZdWOOu2bY%7wrw*ceBORGcU4~4=Hyo6s}uMtLuAEYvVh4rAZ%YJp&tmMP8~0X1;_IY#LlOoFbx78Zo8*MXvs!~ z&4GCHt*v&D>5eNU>epr+@}`f|u_qL5<%fx+ERWUz4e!JnG|_5zZ~g#3&p$ zkDwaZk)Z6dBWQBk7}1*294cAs6W}gqVZfh=?h!vHrnn@X=NpwZi-&A70t!t>3<&vV z2Fn=O-`|>nQK^ztfwn07EM;G3%K3-wW*7^jFnu9~DsQvKpr-w@gVXHI$t%{_P{fiu zvXIU5r)?Ndm_SzFirI#Ljm3rKifHEu7cAxwH`v*1GLSRiBKX+g*g7h(=aGJ+x7Xp- zOfUW>L#e3bxdde=_fy*>pCnnexka7?b!OjHgJa6x(PoQSF*EyqAZN2O6woWNWQW~a zod;5j?q6UjoU^yuZE!=*TTL=&<5Lq$N?2Xtx?+yE$onl9>(-#-7uusQBM8_j?Uo4b zA?z)l`;}i!Cqy4!0+gqNjRS5bPp`nMofH7*i4hB=kcWt#&N#A7!USL{hFJ9Mm%Fw4 zZ3-JhJ-2MA>$n2|&{4FiOKX#VSs#3Po3I>!g$iRlG64+1m_`AZycq|ujxVc`ioy2E z^qB+s3TAz6cXqX*OaGOXoPu@S!!xFz<}=*z>8pvs9itJ+vkqdPu4xr5*{%gk6PjHh z<=Jd=l|k%0UrRtE&)OyRJ&sj`UqESikIH0uU&EyyFF+OR&|B1|NM3?TUW_1W<# zM~(uik|`i>KY3TB@9&;r9^l+DV)*>yvJSb}d!?s?R3T6WJ!GJUJCKMQ^()KbR?>M| zX4rut7Li>z@I{F;;49|VUewPt)hkv(`p0w$;T#r7g)OfOD3v=TMV4f~@epGk^A-aNz}NW9UgnaoafQJyJk_TcGWsFc+hv!zrYB+D*=zZaR`3MkclXLtEou> zX(bf1@WR}Q0j9Lk$Y@kAFSYY9I~!SkM**j#`^$v9qVT9l>{o41#2S;c`lR)5f~HZA z!>|zFLT!=dYy>7{>S)~zww`y5St`B<>^GfY8cYXMR+^T|Tjvbdymz{OS4B~r6xp$w z&pJ$eLP#*Vh0Qm&&euuSNkOgxP)*HOMCq%XH)90Dk5rzH&CXqJFH;ZP0r;#HYl`ba z8`nSNQYY!7-)DjZvA(J6QPBSY)hvtMBwq6~*=~lkbhmDchS)9HN3f?(KZ~9`B?q~1 zXhi`_Yz~i;ySqPpaR8o}A_lvS$A!3t89Zm|#}B_gR9l;sTcTL?S(=eV_cK!SBBu{s ztQrfEpK})$#R-filN56x;Ra3Hu}vgtBsu2KthkK@lVx5q&~v3Tr<3zd$`9Suq!p=q z#75Y@L6XcQaz5Thc14}${>i->x1p z3QzJdU2Is+$>)+XWSL%6tjnVjbD<~HQ=*63my)7ZESRyRFu-O`s@XZsv{Bl)f6LdX z2uvq3%3?8e0Woju3vO^5bLi@zu1d3Rt;+s?+qc5E)X7>Ms*MTEj==n(l2!^TlCO zPGkGbP#sQT!iOI+Vc6F}DW2ofUn1&x^U5MuQ7wh65cvi^t!bT|RL?nC9kO3GYmiA_ zpp29|Xu2iYV(o;HKN$(i#4;M4>BgFQ=4^d*U+`h;a?MK-TFDV?k%Q1Mwx|_z#iyl6 zvaB!;O>4jT@T%gkNBLh@pQlhgP6ujHTm?#au$2|0%k4njmSDCe@7ItWeoKb0_7k(lvKXV*ocbjqYa0tntdP93y2ibi;r&UDA#Z z>m*_dYjfUY2ON9ntDab$gYCT55{hllX2`JjQ}egwH||a@q|@sIhG9iN{fCmQMp|Wj z9|}#YNyFzG+5{B;o9)H($-`9OVYyH>r;(6Y<7B6J! z>^*yb&*MCf&moDLd6UGjmB8NTa%lcMO)Tu>=h|DEjJaMNa(g4G3~*ePyAmtmIlV&V zq4GTtL)piKyB%^iX(D+Uk9gmwp7{6LK7BZV2x{2pGst_Lj{~0cU$7NAG}a84O%_Wk zcWCWciRX#mR1S+~0>QqN=@i&|{aPsrrc+(R@qVECJiXzh1-A{*VtG1!W3cM5x1+>6 zW{Y!uXTgZ|h%jVJTiUBmqg>BpDe>}qpFrtu)&3?nJT_xFz7(?`O%^Ql;-kiLl?0F4 zI7i^2pE9;K|Hz`IfhnuRBAz~f!;`JBQ9wrAMfyA}GP~~+YVUQjUS0xOa_pK4qjk>V ziP+YV2^ba!#X|v1t*BQiGtZtE-ttWa4Rh!Q0PkGV?O?Ejg*rX7r;b*I-sVf+N}y-# zB6$PC{$_kbhBR$w^Ue$){iTlAlKf))&6Z;(obLQIaFfsK<8RODmj%#{RJi(-^t1>) z^Ba;rHtej9KZXt=Mp~~j*p9=r9iHW>2;VW7e)WV=qWI3w!XQH}Hlw9P#?+>5_Cqqu zw9Q2LbgocH?h#p%0MPI)-W?<$BO(N5jw(4@o&_*wFV->P*3+=`=0Q95LG&l*3xRymj%aA52vvocfu{}UCb=~5h(@(Cv9jDvRN|q62dq z4QKys4g2q!O1t6s=Vf-Z6z44k-RMgj5nbJq&D`nhJ*57%tZG6q*vQ<}{Lb!0TpVMXqV$l&;Jb23~GeMwWDsYjSMXl?q<5pc5Yt?Y2T?F7NTwa}Gx z7iyvbo7f$IP}<~^J0(Z|ce^7W?mD@Ze7}wBY`JSiy_)RG!okc>6=z~UlBWk5CT02Y z_WJa)D}a3_hkN;MUtNd|rl(4e$bHOxO4r$;+eqnxrTW+nIR0ri2IlR)xKg+3`4Glp zG6Z2kiDN&K!SF=TlQaJ63{Qp_$9rjnzlc=}Godhy4#I+g!Miymd@u5|yLMH4HH$Io zaEEu`Lfex$)pbjCVeb03=n zgI{@Hn2f&Z03*XFD{usr$G>=SO&q?KS7u6+>hQv|cOwz*BQwa)3{m=Kc|xJ5$AXQD zcYeyt(uxO_fm{COZb*@tgNTdwR07{^I^g(@#Nl3%hB0fOZK+a?vLI2Cc9$WN@_1P| z@c}%)bPSbDl%6F-h=uji%cQ6D+o;_M4_G1%_u}!%Du(R_9KEL|xsoJtFNhxFJUFL; zXzD?Z>AfJc>PZoUobk_#?4&WZ5-5QB+s5>O_+5Nd)-6s?I7RroaPY>9s=HgE7rf%R z5$qO@a?Qz7S5*fASFQNADW$cHMg6F0I|9V?LmlCssuBcW4h1dPg+!LR_rn9dpDzuD z1-A2w4Wx#+otUN8iiO|I3OriB$x4nNGHFCHPEo8YakBo&z5FV;;K}Q38~4(1!7iMk z{{4MGb{BR#am(|C=p!3mST83(@N1k?(bWZ*z(_kvfe2rDX;NH&>obdo)V7t@Evx3- ze73`;5M{C2_x!VLhj~usFO5__#)|E1#OGC;%mOU3hS`nJ(!JfUm_GFvvkBa-Ud`oY zrPP{^yAOXHdXnzZ%I64;&%-%+oRp9nSv60@4qMIY zFQ-1TULs)zIB9_LwPf(0FpJLNO%B}oV9jRC7-)BGa^i50$djD;yv6$XmSHp4!N%4uu} zy|`odpw?HT3#=0>NBn6oO;W39fh9;L%JP_fc2Vs1>d+6qky@Dz^@;Al6W!tZ>hstp z?Sya|>)65sY=%vvK6?XIS#t+@6ibF*rsp0!aJ#1t8}iahCon`dN6{M2Hxxo=UMTZ+ z6KGmUw3Bvs-)F_LiG2qlS~^?9P~RxYcnj2P425e|1=IR6(X$cGSrw#j8RD_{Kas^?es`C;`2cK3>qTqEmTD+onTnC-P5Gj9Nfpz$!Sr!$4585LPXhxc|4Hed?Rk&d)T65!ZL zuMY@fS6ZATMpu-le^L9Hx69tA=!T62N0mu*RHhWmdo!w8hwM)HejPf|#Y@ZqoyzKq z_+j&XPAksOW-UBfLQ(`3r*`#46sV&6U;>mp-|CS`85SGPks95gjOxb#p5gl+i>LW} zwyry$AB^$NaBh6*yNtBpZ1$nP-fu zKUWMR70g8Es7OCth8`AK8b;qo5{cwlEdcI6ZBtPaQx5FR2CBzV@oHCA+8adEm9le_q)98+NorW6%ANF$wSVOC01yiz_M?jzrGn@wD z?yvNgyz@!-vuQ73rrca2iFLIIS2nQnl3-5|G>-sIm#Nd)`KK>(rJ zN5I4YKrh4_7-iGsr#0>A$4$s!GG1$&pfek*n7vkf$rWNi&H{{~Ewz*VDho@n{wdZE zu+`@SZvH;q!=DV@Tcg$;|iK@!^Jl^-(g6 zQ%?xy>}7k5k?Im~V!ik3 zSBwjT@-6#1@L~bn_>q<15gx$C2dX^?1bvuDRSPd?J8(83Yq?;di;K}V93eSxxA8$+ z&rkrnpI>iQIA8izE0L0{O(_ zj_>@eU3Iu}jFlllbg#@bwEJD|mAx*bQEX{MF_L`i=axW-ju9i_!3eZ17_wIfB+Pk| z80G>I<1=cqp`EFT#4tTKH=A+iC4MbSt94a;7m421mG1&qd7SCXQL^V$m;@iSwaMKhn{G0Bg>!nz}< zQa|;b&_>|heY8Yaka6*xT0RYkWnO0~2$g-Ra1Z7Zu>A}O?GG|-ae7p{Jley_Bq+D~ zhqId4a8Z(gMGR9_UxxHdRm)IG53yoP{k>QWmPO+6{8N<#P_1JNgf<=j3PTu>p9e&e zU1)D<13kCXnzQ)eDiD%w>0sBJXV3yLo_h`3mLca%UARgY$!HUuAEXCf`$kRt7w1?( z8u#RrR0Cx)z@kf+Dd|8V;ad7fHWq#%ShTkU9BY?W86>O>oyShCi z+6qDuMxDJW*xLaLMEgIycZbC>r`Yix|2VBEtvwN;z6F5vrPW|XYkJJMS>Yg@`1E}} zI|F^~RK~ul8(M}Q`K{g5;hl!BDjN9>ouKbtP6{w)k_pXb81hM!5g1Z+2C&1M8dK9_ z4I6hO-SMekW^q#CaH)}5*|3e1pfs?wjM{P<{*?hHb@Er$O`dX85m9o-yR6A|U^>>8 zC-dM!T#&A5ndk!Dl*jmQW1VbrtKSX3Bpzu6oLokYrd(}(DMfix58GCm(hlgYBt}AA zQeMIvU{>~yxc(KCe+wnS69n*4?cDSM5U54qD*cZ>qA%@oNP+73@KcSrOv?4j>nN`Z zNVT>i2pfUoHBBe<(X=cW5bQHl3i@3>fWw`9*xt%l8$enDOhm7YvvS|8w&OvcI-_Hm z02T3i%c@|Ek-KdPGbWNF0%*K5bd<;yei8ey%r93B6n!~qMly=YY;JasR1HUzl@cbz zqVoA@bETH!Bygl+L^!8_!BXWcoot3ws`ERuXH;IjN8GJV5jZry7NY0hrowOAukjmpEa~-nYkhYhfKkft&iD9Z01Bm!M_xPwhlQKXqiLn&2e{|lh z-K-mz(1mksS`<&7z!azyJ%(GB1lH?nacXP3*CL>!4vXVjHy~GXm@((L(u!`>#F~6L z+&1_lkeFSh$eoV{WA!nUB;a8rQK?f=JDI$5q6o86&bBRozzA33abRD?S_VS+BA;JZ zH9!s{3bpZ7#!D!p1+8>|oi>4=QmN|4E@0Cmv9ZcN6NtD7`Z78rC>@)g7*hxZD4nL* z2WJV|^2?4R>h4f|Wp}MTM3P~#q?FMtb70v>esu-#B*KSq72^`fr?(|V%3MOC@LHTw zVuwykFD5OVS$i6loC!%U3 zi49gcY)Yj-O>vTd&U@M)nk#~O;`-k-6<5$gTN#^$pH7zBrQJ~)HIszpPHD%SqzDkN zNMFPY_ktRe@p|UASLp=Rl4YIG?I8HEAE$h-2$L%xx;H^AxUHKnA;~te1k_T!APWu3Uzi6(r z&0iVaxIEmgr`|+cQXWzz5UVgH;O}X5Et|7)tO|B9e4CG0?aL`K8#~f$`4}Ah&5f2-BoLd#^`Hpu(jzeFn(b&oSMYHvKOj8J+QXQa1GW~=hGmc!*~wpqp? z(Q_7DdY4ys3A6voO1hC0Lft#)k2XXaYsK+jKzz%=muzACL`~(maCW;!hOW6C5Sf$m zKc6j#5efs!Yxb{`rdafbS&4qUOaU>6bvUe{KU{%@B#W7sTA;2RC`hKM>L&X&>Vi?R z^6(2!0=pd*#3oyjOwU*Nvri>7`41r}ePy{oU~z*cLD?A&bzPQa|5EP~(WlAM5QPQB zChlCjO};RT$*&2S2n|MxH*h>F!Fw*gUV~~dT>7r5;ZFSsRL8YMhn$_~;ro2tH~Ga? z50$rA!#bnU&pJ*~0j{VOlgC9FlNP;6$?rQ#$}`ypl?**fNJ`bMJ0d2nbtz@Ve`i0* zc>ql9WV4e)LlD(3%S@CwPx{C`w;$BDy0ULVVGDdVi?5c^vPd#pbEA7eszLWJLMzNq zAL(Qp0H^@?8-@a7hGJV8#cGVUz>2Ke%7bNs<}n%)!Unfr_{O3efXCSq75In4%n@R% z*-LBk#}Wg0JjKqL4lIq}IYHF7d%EKa>?Fo5o#kf#Dn=alP~6F1^slV!JnG)%HmL0D zxI+nXmx&Ex?pQg*NvO}9SANB`k7MLh+J8G~D9AMfdDO%X;!vKd6a4xnZfdzQ6hD0g zzH@!V25fDL=N!ZPWkccLRhpDWi-PzN(~1BI{t1ef35EPz+{Dt;AJ+XA*#H|g!v;g3 zM6R}p?V}=+VS(B~>@o$0A>gWP>%1m9fy9?3^Nj>n4!_!BJ^#pUzrD#C+uwY?mRf5j z`!xLYbit?jcdF>gH#L=vYd(>a4)f{>d8H2>8z=yx3+*%nQQ{97h#xxA27=I+$4PPa z?Q_*HIG7kBoO<&>^H%69EJ06J-A@JB4O^|6vgW4eOprzX%r86Tt$2R$S3FPlv$>9> z)(5bx*u&k}D60#oN*KzZok4&DsHZ=elY0DBbeLn1QlYT@$Q$ufoU6P$ z<~i&EyRjjRk>A`NA&1`2fp{(Zoem>KhC4bqD%8WMy&ujDGnA2{{-(R=3!erS&0+TWTVzKbezNR=rM)!QG_zzQfRBvE^44*-P zZ+epcM#Q;PEFO7s5iMa6KO1%TuNOhZ+o@A(J+TQ|nnqnkf@uSF93^FnB0h`0SgVn^ zN{cj7cw5w>N^}F>sP-GgNr0HuZuLXh`LEq1?Zv@&8I6HU6>Lh*vz>0tZSS+u1grma zES(-7+f-WqgQNm#gHq=*J&o0=jULi|>bj>MF>ITZ`bZu2@7lmaLii9)9IfqS@*Qr1 zr!wKTvD18lc_$xaS<|TK({~%MzIdC9$^^4zz}yo6%HtQ%!qAe)3lP4kjkUG)NGLIF z+XiL_*1~f|_s=trbuPL`vWE7|31q_AH?U!^dR4P23S{^q8#Cfg2=rVk{Q5tjb2MlK21(w-vYOVgnnDDr5R1!-rX>br4Eaww~Mg0>Eg( z{u3r2{P}~S5LdwY8rpz$CN;i>q zgH@T+1QwW*J&NHkV0`^z)ebW|ql?KlP9SioIq=-kmhXsP)TOWg^K0A7U%cNbxHoE7!70Q78RV~c-1%ok*4I9j9N$06PZ_4K#EO{t<8wM z5{|V?p!6l>MKMxen;F_;*}H~#aIUV5ZpYF+=3#r<&ECCe`22V8xr;!?WaUJOEi}!c zH&AgB$S}SUC%=Os(M;FzH}S{osc|#JGeyOsgEhNBbG6EOTdjA!Q|UMSAG!v8DjLiV zs0)b;Bqqgb4>=n4^}GpXgH-Fe2v=NOGcX^Yqc3`$d!s<1p@mXx9XoMkO z(T8+=Y!jR0LgZ@2B{aHsg)JJT}}4w4kockg>ixcouIscFlg|yX+&r}6@`XHo=F(pT zv~pbnIG+;dXK1TII$QlNG8K*N->Z8S#IH~IX+6WI^nx`LP4?l$NbOSbt9IbWJ__|_ zFN+yx(U<_nmlCQm{1YC_{_J`0ADCyY_?e=`gfg^klfDO-KuuHg0><^tUj442_*431 ztuZ1;LR;hZX`R-F(xUB~={{V+4?uj!xs~nlPqE^9j~qLY>DiFZ^DQ8vMj%B`h>K|> zHjh5)Iifj6SSR~qv<*$jlvRMEb=4iC+QAbWp8GEu_#vn znt{py%9laCHUVEq9XS2#SM*h5+RMy5f`lKg39+b(28n5nqe)@WH^og;Ic0!x3lDKg z+CNjB?`rl7MO3Z5XX+8rLl_w3K;B7MK>b-lMp(xxUjC~`Fl6(uT=8kMyQQ+UFLp@r z1@^irWxzh)3@Sw164FKT=H4`Xs#4A?EU486KxD_E5 zVtxHGiE3ilhYsI?fD=g+ym~&QDyStp&sYkIl!!cEW!SdRqcsb3Rax1GCHFKAAtM?!&SK>gNc+PuqfxEcVWy_8&l!`;JoA8` z&Tkn&q>w55a@EhT&_?Z(k4SFbTe4487fFQJ!4;C46WGd#t4x2^xE}H zzsG=@80MyI!5rgsUmBTG?`G0)~{NpEYo{+L=CKbG2g?*a=YY*8Cy> zWNWKSeix$}%)oVZb;uB`Y^uR2B_{77ps&Ex2WJxFe6XU8 zRV((0{4-8=WSD7@?#