Skip to content

Commit

Permalink
Merge branch 'main' into hod/unicode
Browse files Browse the repository at this point in the history
  • Loading branch information
0mza987 authored Oct 12, 2023
2 parents dddb42e + 5ed0e82 commit d91b73f
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 2 deletions.
23 changes: 23 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM python:3.9-slim-bullseye AS base

RUN set -x

RUN apt-get update \
&& apt-get -y install curl \
&& apt-get -y install net-tools \
&& apt-get -y install procps \
&& apt-get -y install build-essential \
&& apt-get -y install docker.io

# specific pip version to workaround: https://github.com/conda/conda/issues/10178
RUN pip install --upgrade pip==20.1.1
RUN pip install ipython ipykernel
RUN ipython kernel install --user --name aml

# FROM base AS promptflow
COPY default_requirements.txt .
RUN pip install -r default_requirements.txt

RUN set +x

CMD bash
17 changes: 17 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Devcontainer for promptflow
To facilitate your promptflow project development and empower you to work on LLM projects using promptflow more effectively,
we've configured the necessary environment for developing promptflow projects and utilizing flows through the dev container feature.
You can seamlessly initiate your promptflow project development and start leveraging flows by simply using the dev container feature via VS Code or Codespaces.

# Use devcontainer
1. Use vscode to open promptflow repo, and install vscode extension: Dev Containers and then open promptflow with dev containers.
![devcontainer](./devcontainers.png)
**About dev containers please refer to: [dev containers](https://code.visualstudio.com/docs/devcontainers/containers)**
2. Use codespaces to open promptflow repo, it will automatically build the dev containers environment and open promptflow with dev containers.
![codespaces](./codespaces.png)

### Notes
1. If you only want to try out promptflow without developing promptflow, you can simply install Docker and use promptflow within Docker without the need for using DevContainers functionality.
1. `docker build -t promptflow_container`
2. `docker run -it promptflow_container`
2. When using the dev containers function, the promptflow and promptflow-tools installed in the container are the code of the current repo.
Binary file added .devcontainer/codespaces.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions .devcontainer/default_requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
azure-cli
azure-identity
opencensus-ext-azure
promptflow[azure]
promptflow-tools
25 changes: 25 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "Promptflow-Python39",
// "context" is the path that the Codespaces docker build command should be run from, relative to devcontainer.json
"context": ".",
"dockerFile": "Dockerfile",

// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},

// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"ms-toolsai.vscode-ai",
"ms-toolsai.jupyter",
"redhat.vscode-yaml",
"prompt-flow.prompt-flow"
],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip install -r ${containerWorkspaceFolder}/src/promptflow-tools/requirements.txt --force-reinstall;pip install -r ${containerWorkspaceFolder}/src/promptflow/dev_requirements.txt --force-reinstall;pip install -e ${containerWorkspaceFolder}/src/promptflow-tools;pip install -e ${containerWorkspaceFolder}/src/promptflow",

"runArgs": ["-v", "/var/run/docker.sock:/var/run/docker.sock"]
}
Binary file added .devcontainer/devcontainers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions docs/how-to-guides/deploy-a-flow/deploy-using-dev-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ an example to show how to deploy a flow.
Please ensure you have [create the connection](../manage-connections.md#create-a-connection) required by flow, if not, you could
refer to [Setup connection for web-classification](https://github.com/microsoft/promptflow/tree/main/examples/flows/standard/web-classification).

Note: We will use relevant environment variable ({connection_name}_{key_name}) to override connection configurations in
serving mode, white space in connection name will be removed directly from environment variable name. For instance,
if there is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the
function will attempt to retrieve 'chat_deployment_name' from the environment variable
'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the original
value as a fallback.


The following CLI commands allows you serve a flow folder as an endpoint. By running this command, a [flask](https://flask.palletsprojects.com/en/) app will start in the environment where command is executed, please ensure all prerequisites required by flow have been installed.
```bash
Expand Down
6 changes: 4 additions & 2 deletions examples/flows/standard/gen-docstring/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
from diff import show_diff
from load_code_tool import load_code
from promptflow import PFClient
from pathlib import Path


if __name__ == "__main__":
current_folder = Path(__file__).absolute().parent
parser = argparse.ArgumentParser(description="The code path of code that need to generate docstring.")
parser.add_argument("--source", help="Path for the code file", default='./azure_open_ai.py')
parser.add_argument("--source", help="Path for the code file", default=str(current_folder / 'azure_open_ai.py'))
args = parser.parse_args()

pf = PFClient()
source = args.source
flow_result = pf.test(flow="./", inputs={"source": source})
flow_result = pf.test(flow=str(current_folder), inputs={"source": source})
show_diff(load_code(source), flow_result['code'], File(source).filename)
2 changes: 2 additions & 0 deletions src/promptflow/promptflow/_sdk/_serving/flow_invoker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
get_local_connections_from_executable,
resolve_connections_environment_variable_reference,
update_environment_variables_with_connections,
override_connection_config_with_environment_variable,
)
from promptflow._sdk.entities._connection import _Connection
from promptflow.executor import FlowExecutor
Expand Down Expand Up @@ -61,6 +62,7 @@ def _init_connections(self, connection_provider):
else:
raise UnsupportedConnectionProvider(connection_provider)

override_connection_config_with_environment_variable(self.connections)
resolve_connections_environment_variable_reference(self.connections)
update_environment_variables_with_connections(self.connections)
logger.info(f"Promptflow get connections successfully. keys: {self.connections.keys()}")
Expand Down
23 changes: 23 additions & 0 deletions src/promptflow/promptflow/_sdk/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,29 @@ def _match_env_reference(val: str):
return name


def override_connection_config_with_environment_variable(connections: Dict[str, dict]):
"""
The function will use relevant environment variable to override connection configurations. For instance, if there
is a custom connection named 'custom_connection' with a configuration key called 'chat_deployment_name,' the
function will attempt to retrieve 'chat_deployment_name' from the environment variable
'CUSTOM_CONNECTION_CHAT_DEPLOYMENT_NAME' by default. If the environment variable is not set, it will use the
original value as a fallback.
"""
logger = logging.getLogger(LOGGER_NAME)
for connection_name, connection in connections.items():
values = connection.get("value", {})
for key, val in values.items():
connection_name = connection_name.replace(" ", "_")
env_name = f"{connection_name}_{key}".upper()
if env_name not in os.environ:
continue
values[key] = os.environ[env_name]
logger.info(
f"Connection {connection_name}'s {key} is overridden with environment variable {env_name}"
)
return connections


def resolve_connections_environment_variable_reference(connections: Dict[str, dict]):
"""The function will resolve connection secrets env var reference like api_key: ${env:KEY}"""
for connection in connections.values():
Expand Down
24 changes: 24 additions & 0 deletions src/promptflow/tests/sdk_cli_test/unittests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
generate_flow_tools_json,
refresh_connections_dir,
resolve_connections_environment_variable_reference,
override_connection_config_with_environment_variable,
snake_to_camel,
)

Expand Down Expand Up @@ -87,6 +88,29 @@ def test_resolve_connections_environment_variable_reference(self):
assert connections["test_connection"]["value"]["api_base"] == "BASE"
assert connections["test_custom_connection"]["value"]["key"] == "CUSTOM_VALUE"

def test_override_connection_config_with_environment_variable(self):
connections = {
"test_connection": {
"type": "AzureOpenAIConnection",
"value": {
"api_key": "KEY",
"api_base": "https://gpt-test-eus.openai.azure.com/",
},
},
"test_custom_connection": {
"type": "CustomConnection",
"value": {"key": "value1", "key2": "value2"},
},
}
with mock.patch.dict(
os.environ, {"TEST_CONNECTION_API_BASE": "BASE", "TEST_CUSTOM_CONNECTION_KEY": "CUSTOM_VALUE"}
):
override_connection_config_with_environment_variable(connections)
assert connections["test_connection"]["value"]["api_key"] == "KEY"
assert connections["test_connection"]["value"]["api_base"] == "BASE"
assert connections["test_custom_connection"]["value"]["key"] == "CUSTOM_VALUE"
assert connections["test_custom_connection"]["value"]["key2"] == "value2"

def test_generate_flow_tools_json(self) -> None:
# call twice to ensure system path won't be affected during generation
for _ in range(2):
Expand Down

0 comments on commit d91b73f

Please sign in to comment.