Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
dphuang2 committed Apr 17, 2024
1 parent da0d500 commit 28dcff0
Show file tree
Hide file tree
Showing 3 changed files with 854 additions and 36 deletions.
229 changes: 194 additions & 35 deletions misc/building-ai-applications/generating-guides-from-openapi.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5308,7 +5308,174 @@
},
{
"cell_type": "code",
"execution_count": 176,
"execution_count": 6,
"id": "664772c3-b9c5-411c-8a43-19fd29fb6b8d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"72\n"
]
}
],
"source": [
"import yaml\n",
"import jsonref\n",
"from jsonref import replace_refs\n",
"from langchain_core.documents.base import Document\n",
"from copy import deepcopy\n",
"from pprint import pprint\n",
"\n",
"with open(\"alloy.com.yaml\") as f:\n",
" spec = f.read()\n",
"\n",
"def chunk_openapi_by_operation(openapi: str):\n",
" parsed = yaml.safe_load(openapi)\n",
"\n",
" operations: (str, str) = []\n",
" # 1) list all operations by (path, HTTP method)\n",
" for path, methods in parsed['paths'].items():\n",
" for method in methods.keys():\n",
" # if method is not an HTTP method then skip\n",
" if method.lower() not in ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace']:\n",
" continue\n",
" operations.append((path, method))\n",
"\n",
" # 2) create a chunk for every operation\n",
"\n",
" # 2.a) Dereference entire OpenAPI Spec\n",
" dereferenced = replace_refs(parsed, lazy_load=False)\n",
"\n",
" chunks = []\n",
" for operation in operations:\n",
" path = operation[0]\n",
" method = operation[1]\n",
" chunk = deepcopy(dereferenced)\n",
" if 'tags' in chunk['paths'][operation[0]][operation[1]]:\n",
" tags = chunk['paths'][operation[0]][operation[1]]['tags']\n",
"\n",
" # first tag if possible\n",
" if tags:\n",
" tag_name = tags[0]\n",
"\n",
" # delete all tags on OAS except tag for this operation\n",
" while len(chunk['tags']) > 1:\n",
" for i in range(len(chunk['tags']) - 1, -1, -1):\n",
" if chunk['tags'][i]['name'] != tag_name:\n",
" chunk['tags'].pop(i)\n",
"\n",
" if \"summary\" in chunk['paths'][path][method]:\n",
" summary = chunk['paths'][path][method]['summary']\n",
" else:\n",
" summary = \"\"\n",
"\n",
" if \"description\" in chunk['paths'][path][method]:\n",
" description = chunk['paths'][path][method]['description']\n",
" else:\n",
" description = \"\"\n",
"\n",
" # delete other operations\n",
" for other_operation in operations:\n",
" if other_operation[0] == operation[0]:\n",
" continue\n",
" if other_operation[0] in chunk['paths']:\n",
" del chunk['paths'][other_operation[0]]\n",
"\n",
" # delete empty paths\n",
" for path in chunk['paths'].keys():\n",
" if not chunk['paths'][path]:\n",
" del chunk['paths'][path]\n",
"\n",
" # delete other operations under same path\n",
" keys = list(chunk['paths'][operation[0]].keys())\n",
" for method in keys:\n",
" if operation[1] == method:\n",
" continue\n",
" del chunk['paths'][operation[0]][method]\n",
"\n",
" # delete all components besides securitySchemes (should be inlined from 2.a)\n",
" if \"components\" in chunk:\n",
" for key in chunk[\"components\"]:\n",
" if key == \"securitySchemes\":\n",
" continue\n",
" del chunk['components'][key]\n",
" \n",
" chunks.append(({\n",
" \"path\": operation[0],\n",
" \"method\": operation[1],\n",
" \"openapi\": yaml.dump(chunk),\n",
" \"tag\": tag_name,\n",
" \"summary\": summary,\n",
" \"description\": description\n",
" }))\n",
" return list(map(lambda chunk: Document(page_content=chunk[\"openapi\"], metadata={\n",
" \"path\": chunk[\"path\"],\n",
" \"method\": chunk[\"method\"],\n",
" \"tag\": chunk[\"tag\"],\n",
" \"summary\": chunk[\"summary\"],\n",
" \"description\": chunk[\"description\"]\n",
" }), chunks))\n",
"chunks = chunk_openapi_by_operation(spec)\n",
"# for chunk in chunks:\n",
"# print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
"print(len(chunks))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "10399fd6-23b5-4a6a-8a49-07e65d40b745",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Existing running Phoenix instance detected! Shutting it down and starting a new instance...\n",
"Attempting to instrument while already instrumented\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"🌍 To view the Phoenix app in your browser, visit http://localhost:6006/\n",
"📺 To view the Phoenix app in a notebook, run `px.active_session().view()`\n",
"📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix\n"
]
},
{
"data": {
"text/plain": [
"'http://localhost:6006/'"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import phoenix as px\n",
"\n",
"# Launch phoenix\n",
"session = px.launch_app()\n",
"\n",
"# Once you have started a Phoenix server, you can start your LangChain application with the OpenInferenceTracer as a callback. To do this, you will have to instrument your LangChain application with the tracer:\n",
"\n",
"from phoenix.trace.langchain import LangChainInstrumentor\n",
"\n",
"# By default, the traces will be exported to the locally running Phoenix server.\n",
"LangChainInstrumentor().instrument()\n",
"\n",
"session.url"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "bca59022-7be0-4d53-b8e3-f4d35c2887f3",
"metadata": {
"vscode": {
Expand Down Expand Up @@ -5340,7 +5507,7 @@
},
{
"cell_type": "code",
"execution_count": 177,
"execution_count": 9,
"id": "1a884ea5-1d67-474f-b564-fec4bc9512c6",
"metadata": {
"editable": true,
Expand Down Expand Up @@ -5388,7 +5555,7 @@
},
{
"cell_type": "code",
"execution_count": 190,
"execution_count": 10,
"id": "620a8315-69aa-42dc-892e-e7cc53b65807",
"metadata": {
"editable": true,
Expand Down Expand Up @@ -5498,14 +5665,14 @@
},
{
"cell_type": "code",
"execution_count": 191,
"execution_count": 12,
"id": "e92f61a9-33dd-4ede-9c09-ba5ecd967004",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"To create a journey application using the Alloy API in Python, you'll need to follow these steps. This includes setting up your environment, handling authentication, and making the API request. Below, I'll guide you through each step, including both authentication methods available: HTTP Basic and OAuth2.\n",
"To create a Journey Application using the Alloy API in Python, you'll need to follow these steps. This involves setting up your environment, handling authentication, and making the API request with the necessary parameters.\n",
"\n",
"### Environment Setup\n",
"\n",
Expand All @@ -5517,25 +5684,25 @@
"\n",
"### Authentication\n",
"\n",
"The Alloy API provides two methods for authentication: HTTP Basic and OAuth2. Here's how you can handle each:\n",
"The Alloy API provides two methods for authentication: Basic Authentication and OAuth2. Here's how you can handle both:\n",
"\n",
"#### 1. HTTP Basic Authentication\n",
"#### 1. Basic Authentication\n",
"\n",
"For HTTP Basic Authentication, you'll need your workflow token and secret. These should be stored securely and not hard-coded in your scripts. It's a good practice to use environment variables.\n",
"For Basic Authentication, you will need your workflow token and secret. These should be stored securely and not hard-coded in your scripts.\n",
"\n",
"```python\n",
"import os\n",
"import requests\n",
"from requests.auth import HTTPBasicAuth\n",
"import os\n",
"\n",
"# Environment variables for credentials\n",
"# Environment variables for security credentials\n",
"ALLOY_WORKFLOW_TOKEN = os.getenv('ALLOY_WORKFLOW_TOKEN')\n",
"ALLOY_WORKFLOW_SECRET = os.getenv('ALLOY_WORKFLOW_SECRET')\n",
"\n",
"# API endpoint\n",
"url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
"\n",
"# Replace {journey_token} with the actual journey token\n",
"# Replace {journey_token} with your actual journey token\n",
"url = url.format(journey_token=\"J-VCQoADBJxeHtmdAvFqoS\")\n",
"\n",
"# Request headers\n",
Expand All @@ -5544,7 +5711,7 @@
"}\n",
"\n",
"# Request body\n",
"data = {\n",
"payload = {\n",
" \"entities\": [\n",
" {\n",
" \"branch_name\": \"persons\",\n",
Expand All @@ -5554,7 +5721,6 @@
" \"birth_date\": \"1990-01-25\",\n",
" \"document_ssn\": 111223333,\n",
" \"email_address\": \"[email protected]\",\n",
" \"ip_address_v4\": \"42.206.213.70\",\n",
" \"phone_number\": 8443825569,\n",
" \"addresses\": [\n",
" {\n",
Expand All @@ -5566,57 +5732,50 @@
" \"state\": \"NY\",\n",
" \"type\": \"primary\"\n",
" }\n",
" ]\n",
" ],\n",
" \"gender\": \"male\"\n",
" },\n",
" \"entity_type\": \"person\",\n",
" \"external_entity_id\": \"my_system_entity_id_123\"\n",
" \"entity_type\": \"person\"\n",
" }\n",
" ]\n",
"}\n",
"\n",
"# Make the request\n",
"response = requests.post(url, json=data, headers=headers, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
"response = requests.post(url, json=payload, headers=headers, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
"\n",
"# Print the response\n",
"print(response.json())\n",
"```\n",
"\n",
"#### 2. OAuth2 Authentication\n",
"\n",
"For OAuth2, you'll need to obtain a bearer token using the client credentials flow.\n",
"For OAuth2, you'll need to obtain a bearer token using your client credentials first.\n",
"\n",
"```python\n",
"# Function to get OAuth2 token\n",
"def get_oauth2_token():\n",
" token_url = \"https://demo-qasandbox.alloy.co/v1/oauth/bearer\"\n",
" response = requests.post(token_url, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
" return response.json()['access_token']\n",
"# Token endpoint\n",
"token_url = \"https://demo-qasandbox.alloy.co/v1/oauth/bearer\"\n",
"\n",
"# Get the access token\n",
"access_token = get_oauth2_token()\n",
"# Obtain the bearer token\n",
"token_response = requests.post(token_url, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
"access_token = token_response.json().get('access_token')\n",
"\n",
"# Headers with the bearer token\n",
"headers = {\n",
" \"Authorization\": f\"Bearer {access_token}\",\n",
" \"Content-Type\": \"application/json\"\n",
"}\n",
"# Update headers with the bearer token\n",
"headers['Authorization'] = f\"Bearer {access_token}\"\n",
"\n",
"# Make the request with OAuth2 token\n",
"response = requests.post(url, json=data, headers=headers)\n",
"response = requests.post(url, json=payload, headers=headers)\n",
"\n",
"# Print the response\n",
"print(response.json())\n",
"```\n",
"\n",
"### Making the API Request\n",
"\n",
"The request body should include all required fields as specified by your journey's configuration. In this example, I've included some typical fields such as personal information and address. Adjust the `data` dictionary according to the specific requirements of your journey configuration.\n",
"The example above shows how to make a request to create a Journey Application. You need to replace placeholders with actual data like `journey_token`, and ensure the payload matches the required schema as per your journey's configuration.\n",
"\n",
"### Handling the Response\n",
"\n",
"The response from the API will provide details about the journey application created, including any identifiers and status information. Handle this response according to your application's logic, such as logging the result or triggering additional processes.\n",
"\n",
"This setup should help you integrate the Alloy API into your Python application effectively."
"The response from the API will provide details about the created journey application, including tokens and status. Handle this response appropriately in your application to proceed with further actions or display the results to the user."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
Expand Down
Loading

0 comments on commit 28dcff0

Please sign in to comment.