mirror of
https://github.com/james-m-jordan/openai-cookbook.git
synced 2025-05-09 19:32:38 +00:00
483 lines
17 KiB
Plaintext
483 lines
17 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# GPT Actions - Snowflake direct\n",
|
||
"## Introduction"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"This page provides an instruction & guide for developers building a GPT Action for a specific application. Before you proceed, make sure to first familiarize yourself with the following information:\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"* [Introduction to GPT Actions](https://platform.openai.com/docs/actions)\n",
|
||
"* [Introduction to GPT Actions Library](https://platform.openai.com/docs/actions/actions-library)\n",
|
||
"* [Example of Building a GPT Action from Scratch](https://platform.openai.com/docs/actions/getting-started)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"This particular GPT Action provides an overview of how to connect to a Snowflake Data Warehouse. This Action takes a user’s question, scans the relevant tables to gather the data schema, then writes a SQL query to answer the user’s question.\n",
|
||
"\n",
|
||
"Note: This cookbook returns back a [ResultSet SQL statement](https://docs.snowflake.com/en/developer-guide/sql-api/handling-responses#getting-the-data-from-the-results), rather than the full result that is not limited by GPT Actions application/json payload limit. For production and advanced use-case, a middleware is required to return back a CSV file. You can follow instructions in the [GPT Actions - Snowflake Middleware cookbook](../gpt_action_snowflake_middleware) to implement this flow instead."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Value + Example Business Use Cases"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"Value: Users can now leverage ChatGPT's natural language capability to connect directly to Snowflake’s Data Warehouse.\n",
|
||
"\n",
|
||
"Example Use Cases:\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"* Data scientists can connect to tables and run data analyses using ChatGPT's Data Analysis\n",
|
||
"* Citizen data users can ask basic questions of their transactional data\n",
|
||
"* Users gain more visibility into their data & potential anomalies"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Application Information"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Application Key Links"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"Check out these links from the application before you get started:\n",
|
||
"\n",
|
||
"* Application Website: [https://app.snowflake.com/](https://app.snowflake.com/)\n",
|
||
"* Application API Documentation: [https://docs.snowflake.com/en/developer-guide/sql-api/intro](https://docs.snowflake.com/en/developer-guide/sql-api/intro)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Application Prerequisites"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Before you get started, make sure you go through the following steps in your application environment:\n",
|
||
"\n",
|
||
"* Provision a Snowflake Data Warehouse\n",
|
||
"* Ensure that the user authenticating into Snowflake via ChatGPT has access to the database, schemas, and tables with the necessary role"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## ChatGPT Steps"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"### Custom GPT Instructions\n",
|
||
"\n",
|
||
"Once you've created a Custom GPT, copy the text below in the Instructions panel. Have questions? Check out [Getting Started Example](https://platform.openai.com/docs/actions/getting-started) to see how this step works in more detail."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "plaintext"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"**Context**: You are an expert at writing Snowflake SQL queries. A user is going to ask you a question. \n",
|
||
"\n",
|
||
"**Instructions**:\n",
|
||
"1. No matter the user's question, start by running `runQuery` operation using this query: \"SELECT column_name, table_name, data_type, comment FROM `{database}.INFORMATION_SCHEMA.COLUMNS`\" \n",
|
||
"-- Assume warehouse = \"<insert your default warehouse here>\", database = \"<insert your default database here>\", unless the user provides different values \n",
|
||
"2. Convert the user's question into a SQL statement that leverages the step above and run the `runQuery` operation on that SQL statement to confirm the query works. Add a limit of 100 rows\n",
|
||
"3. Now remove the limit of 100 rows and return back the query for the user to see\n",
|
||
"4. Use the <your role> role when querying Snowflake\n",
|
||
"5. Run each step in sequence. Explain what you are doing in a few sentences, run the action, and then explain what you learned. This will help the user understand the reason behind your workflow. \n",
|
||
"\n",
|
||
"**Additional Notes**: If the user says \"Let's get started\", explain that the user can provide a project or dataset, along with a question they want answered. If the user has no ideas, suggest that we have a sample flights dataset they can query - ask if they want you to query that"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"### OpenAPI Schema\n",
|
||
"\n",
|
||
"Once you've created a Custom GPT, copy the text below in the Actions panel. Update the servers url to match your Snowflake Account Name url plus `/api/v2` as described [here](https://docs.snowflake.com/en/user-guide/organizations-connect#standard-account-urls). Have questions? Check out [Getting Started Example](https://platform.openai.com/docs/actions/getting-started) to see how this step works in more detail."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"openapi: 3.1.0\n",
|
||
"info:\n",
|
||
" title: Snowflake Statements API\n",
|
||
" version: 1.0.0\n",
|
||
" description: API for executing statements in Snowflake with specific warehouse and role settings.\n",
|
||
"servers:\n",
|
||
" - url: 'https://<orgname>-<account_name>.snowflakecomputing.com/api/v2'\n",
|
||
"\n",
|
||
"\n",
|
||
"paths:\n",
|
||
" /statements:\n",
|
||
" post:\n",
|
||
" summary: Execute a SQL statement in Snowflake\n",
|
||
" description: This endpoint allows users to execute a SQL statement in Snowflake, specifying the warehouse and roles to use.\n",
|
||
" operationId: runQuery\n",
|
||
" tags:\n",
|
||
" - Statements\n",
|
||
" requestBody:\n",
|
||
" required: true\n",
|
||
" content:\n",
|
||
" application/json:\n",
|
||
" schema:\n",
|
||
" type: object\n",
|
||
" properties:\n",
|
||
" warehouse:\n",
|
||
" type: string\n",
|
||
" description: The name of the Snowflake warehouse to use for the statement execution.\n",
|
||
" role:\n",
|
||
" type: string\n",
|
||
" description: The Snowflake role to assume for the statement execution.\n",
|
||
" statement:\n",
|
||
" type: string\n",
|
||
" description: The SQL statement to execute.\n",
|
||
" required:\n",
|
||
" - warehouse\n",
|
||
" - role\n",
|
||
" - statement\n",
|
||
" responses:\n",
|
||
" '200':\n",
|
||
" description: Successful execution of the SQL statement.\n",
|
||
" content:\n",
|
||
" application/json:\n",
|
||
" schema:\n",
|
||
" type: object\n",
|
||
" properties:\n",
|
||
" status:\n",
|
||
" type: string\n",
|
||
" data:\n",
|
||
" type: object\n",
|
||
" additionalProperties: true\n",
|
||
" '400':\n",
|
||
" description: Bad request, e.g., invalid SQL statement or missing parameters.\n",
|
||
" '401':\n",
|
||
" description: Authentication error, invalid API credentials.\n",
|
||
" '500':\n",
|
||
" description: Internal server error."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Authentication Instructions"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Below are instructions on setting up authentication with this 3rd party application. Have questions? Check out [Getting Started Example](https://platform.openai.com/docs/actions/getting-started) to see how this step works in more detail."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Pre-Action Steps"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Before you set up authentication in ChatGPT, please take the following steps in Snowflake.\n",
|
||
"\n",
|
||
"### 1. Optional: Configure IP Whitelisting for ChatGPT\n",
|
||
"Snowflake accounts with network policies that limit connections by IP, may require exceptions to be added for ChatGPT.\n",
|
||
"* Review the Snowflake documentation on [Network Policies](https://docs.snowflake.com/en/user-guide/network-policies)\n",
|
||
"* Go to the Snowflake Worksheets\n",
|
||
"* Create a network rule with the ChatGPT IP egress ranges listed [here](https://platform.openai.com/docs/actions/production/ip-egress-ranges)\n",
|
||
"* Create a corresponding Network Policy"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"## Example with ChatGPT IPs as of September 19, 2024\n",
|
||
"## Make sure to get the current IP ranges from https://platform.openai.com/docs/actions/production\n",
|
||
"CREATE NETWORK RULE chatgpt_network_rule\n",
|
||
" MODE = INGRESS\n",
|
||
" TYPE = IPV4\n",
|
||
" VALUE_LIST = ('23.102.140.112/28',\n",
|
||
" '13.66.11.96/28',\n",
|
||
" '104.210.133.240/28',\n",
|
||
" '20.97.188.144/28',\n",
|
||
" '20.161.76.48/28',\n",
|
||
" '52.234.32.208/28',\n",
|
||
" '52.156.132.32/28',\n",
|
||
" '40.84.220.192/28',\n",
|
||
" '23.98.178.64/28',\n",
|
||
" '40.84.180.128/28');\n",
|
||
"\n",
|
||
"CREATE NETWORK POLICY chatgpt_network_policy\n",
|
||
" ALLOWED_NETWORK_RULE_LIST = ('chatgpt_network_rule');"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 2. Set up the Security Integration\n",
|
||
"* Review the Snowflake OAuth Overview: [https://docs.snowflake.com/en/user-guide/oauth-snowflake-overview](https://docs.snowflake.com/en/user-guide/oauth-snowflake-overview)\n",
|
||
"* Create new OAuth credentials through a [Security Integration](https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake) - you will need a new one for each OAuth app/custom GPT since Snowflake Redirect URIs are 1-1 mapped to Security Integrations"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"CREATE SECURITY INTEGRATION CHATGPT_INTEGRATION\n",
|
||
" TYPE = OAUTH\n",
|
||
" ENABLED = TRUE\n",
|
||
" OAUTH_CLIENT = CUSTOM\n",
|
||
" OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'\n",
|
||
" OAUTH_REDIRECT_URI = 'https://oauth.pstmn.io/v1/callback' --- // this is a temporary value while testing your integration. You will replace this with the value your GPT provides\n",
|
||
" OAUTH_ISSUE_REFRESH_TOKENS = TRUE\n",
|
||
" OAUTH_REFRESH_TOKEN_VALIDITY = 7776000;\n",
|
||
" NETWORK_POLICY = chatgpt_network_policy --- // this line should only be included if you followed step 1 above"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"* Retrieve your OAuth Client ID, Auth URL, and Token URL\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"DESCRIBE SECURITY INTEGRATION CHATGPT_INTEGRATION;"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"You’ll find the required information in these 3 columns:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"* Retrieve your OAuth Client Secret"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"select SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('CHATGPT_INTEGRATION');"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"You’ll find the Client Secret in OAUTH_CLIENT_SECRET. Do not include the double quotes when copying the value.\n",
|
||
"\n",
|
||
"Now is a good time to [test your Snowflake integration in Postman](https://community.snowflake.com/s/article/How-to-configure-postman-for-testing-SQL-API-with-OAuth). If you configured a network policy for your security integration, ensure that it includes the IP of the machine you're using to test."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### In ChatGPT"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"In ChatGPT, click on \"Authentication\" and choose \"OAuth\". Enter in the information below.\n",
|
||
"\n",
|
||
"| Form Field | Value |\n",
|
||
"| -------- | -------- |\n",
|
||
"| Authentication Type | OAuth |\n",
|
||
"| Client ID | OAUTH_CLIENT_ID from SHOW_OAUTH_CLIENT_SECRETS |\n",
|
||
"| Authorization URL | OAUTH_AUTHORIZATION_ENDPOINT from DESCRIBE SECURITY INTEGRATION |\n",
|
||
"| Token URL | OAUTH_TOKEN_ENDPOINT from DESCRIBE SECURITY INTEGRATION |\n",
|
||
"| Scope | <empty>* |\n",
|
||
"| Token Exchange Method | Default (POST Request) |\n",
|
||
"\n",
|
||
"\n",
|
||
"*Snowflake scopes pass the role, but you’ll notice the action itself also specifies the role as a parameter in runQuery, so the Scope is unnecessary. You may elect to pass roles in the scope instead of the action parameters if it makes more sense for your GPT."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Post-Action Steps"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"Once you've set up authentication in ChatGPT, follow the steps below in the application to finalize the Action.\n",
|
||
"\n",
|
||
"* Copy the callback URL from the GPT Action\n",
|
||
"* Update the Redirect URI in your Security Integration to the callback URL provided in ChatGPT.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "yaml"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"ALTER SECURITY INTEGRATION CHATGPT_INTEGRATION_DEV SET OAUTH_REDIRECT_URI='https://chat.openai.com/aip/<callback_id>/oauth/callback';"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### FAQ & Troubleshooting"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* The callback url can change if you update the YAML, double check it is correct when making changes.\n",
|
||
"* _Callback URL Error:_ If you get a callback URL error in ChatGPT, pay close attention to the Post-Action Steps above. You need to add the callback URL directly into your Security Integration for the action to authenticate correctly\n",
|
||
"* _Schema calls the wrong warehouse or database:_ If ChatGPT calls the wrong warehouse or database, consider updating your instructions to make it more explicit either (a) which warehouse / database should be called or (b) to require the user provide those exact details before it runs the query\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"_Are there integrations that you’d like us to prioritize? Are there errors in our integrations? File a PR or issue in our github, and we’ll take a look._\n"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.11.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|