Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "llmops_promptflow_container",
"image": "mcr.microsoft.com/azureml/promptflow/promptflow-runtime-stable:20240205.v2",

"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.debugpy",
"ms-toolsai.vscode-ai",
"ms-toolsai.jupyter",
"redhat.vscode-yaml",
"prompt-flow.prompt-flow"
]
}
},

"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "latest"
}
},
"containerEnv": { "SUBSCRIPTION_ID": "${localEnv:SUBSCRIPTION_ID}" },
"postCreateCommand": "pip3 install -r /workspaces/llmops-promptflow-template/.devcontainer/requirements.txt"

}
1 change: 1 addition & 0 deletions .devcontainer/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python-dotenv
69 changes: 69 additions & 0 deletions llmops/common/config_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Configuration utils to load config from yaml/json."""
import os
from typing import Dict, Any
from pathlib import Path
from dotenv import load_dotenv
import yaml


class LLMOpsConfig:
"""LLMOpsConfig Class."""

_raw_config: Any

def __init__(
self,
flow_name: str = "",
environment: str = "pr",
config_path: str = "configs/config.yaml"
):
"""Intialize MLConfig with yaml config data."""
self.config_path = Path(flow_name, config_path)
self._environment = environment
load_dotenv()

with open(self.config_path, "r", encoding="utf-8") as stream:
self._raw_config = yaml.safe_load(os.path.expandvars(stream.read()))

def __getattr__(self, __name: str) -> Any:
"""Get values for top level keys in configuration."""
return self._raw_config[__name]

@property
def model_config(self):
"""Get model configuration."""
return self._raw_config['llmops_config'][self._environment]

@property
def datasets_config(self):
"""Get datasets configuration."""
return self._raw_config['datasets_config'][self._environment]

@property
def azure_managed_endpoint_config(self):
"""Get azure managed endpoint deployment configuration."""
return self._raw_config['deployment_configs']['azure_managed_endpoint'][self._environment]

@property
def kubernetes_endpoint_config(self):
"""Get kubernetes endpoint deployment configuration."""
return self._raw_config['deployment_configs']['kubernetes_endpoint'][self._environment]

@property
def webapp_endpoint_config(self):
"""Get webapp endpoint deployment configuration."""
return self._raw_config['deployment_configs']['webapp_endpoint'][self._environment]


if __name__ == "__main__":
config = LLMOpsConfig(flow_name="web_classification", environment="dev")
print(config.model_config)
print(config.datasets_config)
print(config.deployment_configs)
print(config.mapping_config)
print(config.azure_managed_endpoint_config)
print(config.kubernetes_endpoint_config)
print(config.webapp_endpoint_config)
print(config.webapp_endpoint_config['CONNECTION_NAMES'])
for connection in config.webapp_endpoint_config['CONNECTION_NAMES']:
print(connection)
25 changes: 8 additions & 17 deletions llmops/common/prompt_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from promptflow.azure import PFClient

from llmops.common.logger import llmops_logger
from llmops.common.config_utils import LLMOpsConfig

logger = llmops_logger("prompt_eval")

Expand All @@ -51,20 +52,13 @@ def prepare_and_execute(
Returns:
None
"""
main_config = open(f"{flow_to_execute}/llmops_config.json")
model_config = json.load(main_config)

for obj in model_config["envs"]:
if obj.get("ENV_NAME") == stage:
config = obj
break


main_config = LLMOpsConfig(flow_name=flow_to_execute, environment=stage)
config = main_config.model_config

resource_group_name = config["RESOURCE_GROUP_NAME"]
workspace_name = config["WORKSPACE_NAME"]
data_mapping_config = f"{flow_to_execute}/configs/mapping_config.json"
standard_flow_path = config["STANDARD_FLOW_PATH"]
data_config_path = f"{flow_to_execute}/configs/data_config.json"

runtime = config["RUNTIME_NAME"]
eval_flow_path = config["EVALUATION_FLOW_PATH"]
experiment_name = f"{flow_to_execute}_{stage}"
Expand All @@ -80,9 +74,8 @@ def prepare_and_execute(

standard_flow = f"{flow_to_execute}/{standard_flow_path}"
dataset_name = []
config_file = open(data_config_path)
data_config = json.load(config_file)
for elem in data_config["datasets"]:
data_config = main_config.datasets_config
for elem in data_config:
if "DATA_PURPOSE" in elem and "ENV_NAME" in elem:
if (stage == elem["ENV_NAME"] and
data_purpose == elem["DATA_PURPOSE"]):
Expand All @@ -99,7 +92,6 @@ def prepare_and_execute(
)

standard_flow_file = f"{standard_flow}/flow.dag.yaml"

with open(standard_flow_file, "r") as yaml_file:
yaml_data = yaml.safe_load(yaml_file)

Expand All @@ -110,8 +102,7 @@ def prepare_and_execute(
node_variant_mapping[node_name] = default_variant
default_variants.append(node_variant_mapping)

mapping_file = open(data_mapping_config)
mapping_config = json.load(mapping_file)
mapping_config = main_config.mapping_config
eval_config_node = mapping_config["evaluation"]

all_eval_df = []
Expand Down
58 changes: 26 additions & 32 deletions llmops/common/prompt_local_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from promptflow import PFClient

from llmops.common.logger import llmops_logger
from llmops.common.config_utils import LLMOpsConfig

logger = llmops_logger("prompt_aoai_connection")

Expand All @@ -42,43 +43,36 @@ def prepare_and_execute(
Returns:
None
"""
main_config = open(f"{flow_to_execute}/llmops_config.json")
model_config = json.load(main_config)
main_config = LLMOpsConfig(flow_name=flow_to_execute, environment=stage)
model_config = main_config.model_config
logger.info("valid environment is found")

secret_config = json.loads(connection_details)

for obj in model_config["envs"]:
if obj.get("ENV_NAME") == stage:
logger.info("valid environment is found")
break

dep_config = f"{flow_to_execute}/configs/deployment_config.json"
config_file = open(dep_config)

pf = PFClient()

connection_config = json.load(config_file)
for elem in connection_config["webapp_endpoint"]:
if "CONNECTION_NAMES" in elem and "ENV_NAME" in elem:
if stage == elem["ENV_NAME"]:
con_to_create = list(elem["CONNECTION_NAMES"])

for con in con_to_create:
for avail_con in secret_config:
if avail_con['name'] == con:
if avail_con['type'] == "azure_open_ai":
connection = AzureOpenAIConnection(
name=avail_con['name'],
api_key=avail_con['api_key'],
api_base=avail_con['api_base'],
api_type=avail_con['api_type'],
api_version=avail_con['api_version']
)
pf.connections.create_or_update(connection)

logger.info(
f"{avail_con['name']} created successfully"
)
webapp_endpoint_config = main_config.webapp_endpoint_config

if "CONNECTION_NAMES" in elem and "ENV_NAME" in elem:
if stage == elem["ENV_NAME"]:
con_to_create = list(elem["CONNECTION_NAMES"])

for con in con_to_create:
for avail_con in secret_config:
if avail_con['name'] == con:
if avail_con['type'] == "azure_open_ai":
connection = AzureOpenAIConnection(
name=avail_con['name'],
api_key=avail_con['api_key'],
api_base=avail_con['api_base'],
api_type=avail_con['api_type'],
api_version=avail_con['api_version']
)
pf.connections.create_or_update(connection)

logger.info(
f"{avail_con['name']} created successfully"
)


def main():
Expand Down
30 changes: 11 additions & 19 deletions llmops/common/prompt_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from azure.ai.ml import MLClient
from promptflow.entities import Run
from promptflow.azure import PFClient
from llmops.common.config_utils import LLMOpsConfig

from llmops.common.logger import llmops_logger

Expand Down Expand Up @@ -80,21 +81,14 @@ def prepare_and_execute(
Returns:
None
"""
main_config = open(f"{flow_to_execute}/llmops_config.json")
model_config = json.load(main_config)
config = LLMOpsConfig(flow_name=flow_to_execute, environment=stage)
model_config = config.model_config

for obj in model_config["envs"]:
if obj.get("ENV_NAME") == stage:
config = obj
break
resource_group_name = model_config["RESOURCE_GROUP_NAME"]
workspace_name = model_config["WORKSPACE_NAME"]
standard_flow_path = model_config["STANDARD_FLOW_PATH"]

resource_group_name = config["RESOURCE_GROUP_NAME"]
workspace_name = config["WORKSPACE_NAME"]
data_mapping_config = f"{flow_to_execute}/configs/mapping_config.json"
standard_flow_path = config["STANDARD_FLOW_PATH"]
data_config_path = f"{flow_to_execute}/configs/data_config.json"

runtime = config["RUNTIME_NAME"]
runtime = model_config["RUNTIME_NAME"]
experiment_name = f"{flow_to_execute}_{stage}"

ml_client = MLClient(
Expand All @@ -110,12 +104,11 @@ def prepare_and_execute(
resource_group_name,
workspace_name
)
logger.info(data_mapping_config)

flow = f"{flow_to_execute}/{standard_flow_path}"
dataset_name = []
config_file = open(data_config_path)
data_config = json.load(config_file)
for elem in data_config["datasets"]:
data_config = config.datasets_config
for elem in data_config:
if "DATA_PURPOSE" in elem and "ENV_NAME" in elem:
if (stage == elem["ENV_NAME"] and
data_purpose == elem["DATA_PURPOSE"]):
Expand Down Expand Up @@ -146,8 +139,7 @@ def prepare_and_execute(
if nodes.get("type", {}) == "llm":
all_llm_nodes.add(nodes["name"])

mapping_file = open(data_mapping_config)
mapping_config = json.load(mapping_file)
mapping_config = config.mapping_config
exp_config_node = mapping_config["experiment"]

run_ids = []
Expand Down
18 changes: 6 additions & 12 deletions llmops/common/register_data_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from azure.ai.ml.constants import AssetTypes
from azure.identity import DefaultAzureCredential
from llmops.common.logger import llmops_logger
from llmops.common.config_utils import LLMOpsConfig


logger = llmops_logger("register_data_asset")
Expand Down Expand Up @@ -71,15 +72,11 @@ def generate_file_hash(file_path):
args = parser.parse_args()

environment_name = args.env_name
main_config = open(f"{args.flow_to_execute}/llmops_config.json")
config = json.load(main_config)
flow_name = args.flow_to_execute
config = LLMOpsConfig(flow_name=flow_name, environment=environment_name)
model_config = config.model_config
data_config = config.datasets_config

for obj in config["envs"]:
if obj.get("ENV_NAME") == environment_name:
model_config = obj
break

data_config_path = f"{args.flow_to_execute}/configs/data_config.json"
resource_group_name = model_config["RESOURCE_GROUP_NAME"]
workspace_name = model_config["WORKSPACE_NAME"]
data_purpose = args.data_purpose
Expand All @@ -91,10 +88,7 @@ def generate_file_hash(file_path):
workspace_name
)

config_file = open(data_config_path)
data_config = json.load(config_file)

for elem in data_config["datasets"]:
for elem in data_config:
if "DATA_PURPOSE" in elem and "ENV_NAME" in elem:
if (
data_purpose == elem["DATA_PURPOSE"]
Expand Down
22 changes: 11 additions & 11 deletions llmops/common/scripts/az_webapp_deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ set -e # fail on error

# read values from deployment_config.json related to `webapp_endpoint`
env_name=$deploy_environment
deploy_config="./$flow_to_execute/configs/deployment_config.json"
con_object=$(jq ".webapp_endpoint[] | select(.ENV_NAME == \"$env_name\")" "$deploy_config")
REGISTRY_NAME=$(echo "$con_object" | jq -r '.REGISTRY_NAME')
rgname=$(echo "$con_object" | jq -r '.WEB_APP_RG_NAME')
udmid=$(echo "$con_object" | jq -r '.USER_MANAGED_ID')
appserviceplan=$(echo "$con_object" | jq -r '.APP_PLAN_NAME')
appserviceweb=$(echo "$con_object" | jq -r '.WEB_APP_NAME')
acr_rg=$(echo "$con_object" | jq -r '.REGISTRY_RG_NAME')
websku=$(echo "$con_object" | jq -r '.WEB_APP_SKU')

read -r -a connection_names <<< "$(echo "$con_object" | jq -r '.CONNECTION_NAMES | join(" ")')"
config="./$flow_to_execute/configs/config.yaml"
con_object=$(yq ".deployment_configs.webapp_endpoint.'$env_name'" "$config")
REGISTRY_NAME=$(echo "$con_object" | yq -r '.REGISTRY_NAME')
rgname=$(echo "$con_object" | yq -r '.WEB_APP_RG_NAME')
udmid=$(echo "$con_object" | yq -r '.USER_MANAGED_ID')
appserviceplan=$(echo "$con_object" | yq -r '.APP_PLAN_NAME')
appserviceweb=$(echo "$con_object" | yq -r '.WEB_APP_NAME')
acr_rg=$(echo "$con_object" | yq -r '.REGISTRY_RG_NAME')
websku=$(echo "$con_object" | yq -r '.WEB_APP_SKU')

read -r -a connection_names <<< "$(echo "$con_object" | yq -r '.CONNECTION_NAMES | join(" ")')"
echo $connection_names

# create a resource group
Expand Down
Loading