GPT Actions library - Box

2024 年 8 月 2 日
在 Github 中打开

本指南详细介绍了如何将 chatGPT 与 Box.com 帐户连接,GPT 需要两个操作才能从 Box 中提取数据。GPT 将直接与 Box API 交互,但需要中间件(即 Azure 函数)来正确格式化来自 Box 的响应,以便下载和读取文件内容。azure 函数操作对最终用户是透明的,这意味着用户无需显式调用该操作。

  • 操作 1:Box API 操作 - 利用 Box API 从 Box 查询数据
  • 操作 2:Azure 函数 - 格式化来自 Box 的响应,使 chatGPT 能够直接从 Box 下载文件

价值 + 示例业务用例

现有的 Box 客户可以利用这些指南来查询有关文件、文件内容和任何相关元数据的详细信息。这支持对 Box 中存储的任何内容进行 OpenAI 驱动的分析,例如可视化数据集以及创建跨多个文件夹和文件的摘要。此 GPT 可以访问 Box 中的文件夹、文件和业务流程数据(例如元数据)。此外,Box 管理员可以使用此 GPT 操作来了解审计跟踪和运行状况检查。

在开始之前,请确保在您的 Box 环境中完成以下步骤

  • 这需要一个 Box 开发者帐户才能开始:https://developer.box.com/
  • 按照 Box 开发者站点创建一个具有 OAuth 2.0 身份验证类型的自定义应用程序:https://developer.box.com/guides/getting-started/first-application/
  • 导航到配置选项卡以获取以下值
    • OAuth 2.0 凭据(客户端 ID / 客户端密钥)您将需要这两个值用于 chatGPT 配置
    • OAuth 2.0 重定向 URI:您将从下面的 chatGPT 操作配置中填写此值
    • 应用程序范围(读取 Box 中的所有文件和文件夹管理企业属性

您将需要保持此窗口打开,重定向 URI 需要从 gpt 配置中填写。

gpt_actions_box_boxconfig1.png.png


中间件信息:操作 2 所必需

确保在您的 Azure 环境中完成以下步骤

  • Azure 门户,具有创建 Azure 函数应用和 Azure Entra 应用注册的权限
  • 本指南中有一个详细部分,介绍了部署和设计函数的相关内容,该函数是封装来自 Box 的响应以便查看文件内容所必需的。如果没有该函数,GPT 将只能查询有关文件的数据,而不能查询内容。请务必在创建第一个操作后阅读本节。

创建自定义 GPT 后,将下面的文本复制到“指令”面板中。有疑问?请查看入门示例,以了解此步骤如何更详细地工作。

**context** 

This GPT will connect to your Box.com account to search files and folders, providing accurate and helpful responses based on the user's queries. It will assist with finding, organizing, and retrieving information stored in Box.com. Ensure secure and private handling of any accessed data. Avoid performing any actions that could modify or delete files unless explicitly instructed. Prioritize clarity and efficiency in responses. Use simple language for ease of understanding. Ask for clarification if a request is ambiguous or if additional details are needed to perform a search. Maintain a professional and friendly tone, ensuring users feel comfortable and supported.


Please use this website for instructions using the box API : https://developer.box.com/reference/ each endpoint can be found from this reference documentation

Users can search with the Box search endpoint or Box metadata search endpoint

**instructions**
When retrieving file information from Box provide as much details as possible and format into a table when more than one file is returned, include the modified date, created date and any other headers you might find valuable

Provide insights to files and suggest patterns for users, gives example queries and suggestions when appropriate

When a user wants to compare files retrieve the file for the user with out asking

创建自定义 GPT 后,您需要创建 2 个操作。将下面的文本复制到第一个“操作”面板中,这将用于 Box 操作。有疑问?请查看入门示例,以了解此步骤如何更详细地工作。

{
  "openapi": "3.1.0",
  "info": {
    "title": "Box.com API",
    "description": "API for Box.com services",
    "version": "v1.0.0"
  },
  "servers": [
    {
      "url": "https://api.box.com/2.0"
    }
  ],
  "paths": {
    "/folders/{folder_id}": {
      "get": {
        "summary": "Get Folder Items",
        "operationId": "getFolderItems",
        "parameters": [
          {
            "name": "folder_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ID of the folder"
          }
        ],
        "responses": {
          "200": {
            "description": "A list of items in the folder",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FolderItems"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:folders"
            ]
          }
        ]
      }
    },
    "/files/{file_id}": {
      "get": {
        "summary": "Get File Information",
        "operationId": "getFileInfo",
        "parameters": [
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ID of the file"
          }
        ],
        "responses": {
          "200": {
            "description": "File information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileInfo"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:files"
            ]
          }
        ]
      }
    },
    "/folders": {
      "get": {
        "summary": "List All Folders",
        "operationId": "listAllFolders",
        "responses": {
          "200": {
            "description": "A list of all folders",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoldersList"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:folders"
            ]
          }
        ]
      }
    },
    "/events": {
      "get": {
        "summary": "Get User Events",
        "operationId": "getUserEvents",
        "parameters": [
          {
            "name": "stream_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The type of stream"
          }
        ],
        "responses": {
          "200": {
            "description": "User events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserEvents"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:events"
            ]
          }
        ]
      }
    },
    "/admin_events": {
      "get": {
        "summary": "Get Admin Events",
        "operationId": "getAdminEvents",
        "responses": {
          "200": {
            "description": "Admin events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminEvents"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:events"
            ]
          }
        ]
      }
    },
    "/search": {
      "get": {
        "summary": "Search",
        "operationId": "search",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Search query"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "search:items"
            ]
          }
        ]
      }
    },
    "/metadata_templates": {
      "get": {
        "summary": "Get Metadata Templates",
        "operationId": "getMetadataTemplates",
        "responses": {
          "200": {
            "description": "Metadata templates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataTemplates"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:metadata_templates"
            ]
          }
        ]
      }
    },
    "/metadata_templates/enterprise": {
      "get": {
        "summary": "Get Enterprise Metadata Templates",
        "operationId": "getEnterpriseMetadataTemplates",
        "responses": {
          "200": {
            "description": "Enterprise metadata templates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataTemplates"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:metadata_templates"
            ]
          }
        ]
      }
    },
    "/files/{file_id}/metadata": {
      "get": {
        "summary": "Get All Metadata for a File",
        "operationId": "getAllMetadataForFile",
        "parameters": [
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ID of the file"
          }
        ],
        "responses": {
          "200": {
            "description": "All metadata instances for the file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataInstances"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2": [
              "read:metadata"
            ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "FolderItems": {
        "type": "object",
        "properties": {
          "total_count": {
            "type": "integer",
            "description": "The total number of items in the folder"
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "The type of the item (e.g., file, folder)"
                },
                "id": {
                  "type": "string",
                  "description": "The ID of the item"
                },
                "name": {
                  "type": "string",
                  "description": "The name of the item"
                }
              }
            }
          }
        }
      },
      "FileInfo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the file"
          },
          "name": {
            "type": "string",
            "description": "The name of the file"
          },
          "size": {
            "type": "integer",
            "description": "The size of the file in bytes"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "The creation time of the file"
          },
          "modified_at": {
            "type": "string",
            "format": "date-time",
            "description": "The last modification time of the file"
          }
        }
      },
      "FoldersList": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "The ID of the folder"
            },
            "name": {
              "type": "string",
              "description": "The name of the folder"
            }
          }
        }
      },
      "UserEvents": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "event_id": {
                  "type": "string",
                  "description": "The ID of the event"
                },
                "event_type": {
                  "type": "string",
                  "description": "The type of the event"
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "The time the event occurred"
                }
              }
            }
          }
        }
      },
      "AdminEvents": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "event_id": {
                  "type": "string",
                  "description": "The ID of the event"
                },
                "event_type": {
                  "type": "string",
                  "description": "The type of the event"
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "The time the event occurred"
                }
              }
            }
          }
        }
      },
      "SearchResults": {
        "type": "object",
        "properties": {
          "total_count": {
            "type": "integer",
            "description": "The total number of search results"
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "The type of the item (e.g., file, folder)"
                },
                "id": {
                  "type": "string",
                  "description": "The ID of the item"
                },
                "name": {
                  "type": "string",
                  "description": "The name of the item"
                }
              }
            }
          }
        }
      },
      "MetadataTemplates": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "templateKey": {
              "type": "string",
              "description": "The key of the metadata template"
            },
            "displayName": {
              "type": "string",
              "description": "The display name of the metadata template"
            },
            "scope": {
              "type": "string",
              "description": "The scope of the metadata template"
            }
          }
        }
      },
      "MetadataInstances": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "templateKey": {
              "type": "string",
              "description": "The key of the metadata template"
            },
            "type": {
              "type": "string",
              "description": "The type of the metadata instance"
            },
            "attributes": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              },
              "description": "Attributes of the metadata instance"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "OAuth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://account.box.com/api/oauth2/authorize",
            "tokenUrl": "https://api.box.com/oauth2/token",
            "scopes": {
              "read:folders": "Read folders",
              "read:files": "Read files",
              "search:items": "Search items",
              "read:metadata": "Read metadata",
              "read:metadata_templates": "Read metadata templates",
              "read:events": "Read events"
            }
          }
        }
      }
    }
  }
}

注意:上面的架构不包含所有可能的 API 端点,请务必编辑架构以从Box 开发者文档中生成适当的操作

以下是有关使用此第三方应用程序设置身份验证的说明。有疑问?请查看入门示例,以了解此步骤如何更详细地工作。

在 ChatGPT 中,单击“身份验证”并选择 OAuth


gptactions_box_gptauth.png

OAuth 连接

  • 客户端 ID - 来自您之前创建的 Box 自定义应用程序的值
  • 客户端密钥 - 来自您之前创建的 Box 自定义应用程序的值
  • 授权 URL - :https://account.box.com/api/oauth2/authorize?response_type=code&client_id=[client 上面的 ID]&redirect_uri=[现在使用 chat.openai.com/aip//oauth/callback 之类的占位符,稍后在 ChatGPT 中创建 Action 时再更新此项]
  • 令牌 URL:https:api.box.com/oauth2/token

您需要保存配置并导航回 gpt 配置选项卡以复制回调 URL,编辑 Box 操作授权 URL 的配置,并将 URL 格式化为 https://account.box.com/api/oauth2/authorize?response_type=code&client_id=[client_ID]&redirect_uri=[callBack URL]

更新 Box.com 自定义应用程序

  • 从 gpt 复制回调 URL,并在 Box.com 中添加 OAuth 2.0 重定向 URI

![gpt_actions_box_boxconfig1.png.png](../../../images/gpt_actions_box_boxconfig1.png)

现在我们已经创建了 GPT 并针对 Box.com 进行了身份验证,我们可以创建 azure 函数来处理响应格式化,使 GPT 能够从 Box 下载文件。

请按照此Azure Cookbook 指南了解有关部署 Azure 函数的更多详细信息。下面您将找到添加到函数的示例代码。

此代码旨在提供指导 - 虽然它应该可以开箱即用,但它旨在根据您的需求进行自定义。


数据流

gpt_actions_box_azureflow.png



现在您已经创建了 azure 函数,添加以下示例代码

function_app.py

import azure.functions as func
from boxsdk import Client, JWTAuth

import requests
import base64
import json
import jwt
import logging

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

@app.route(route="box_retrieval")
def box_retrieval(req: func.HttpRequest) -> func.HttpResponse:
    logger.info('Starting box_retrieval function')
    file_ids = req.params.get('file_ids')
    auth_header = req.headers.get('Authorization')

    if not file_ids or not auth_header:
        logger.error('Missing file_ids or Authorization header')
        return func.HttpResponse(
            "Missing file_id or Authorization header.",
            status_code=400
        )
    
    file_ids = file_ids.split(",")  # Assuming file_ids are passed as a comma-separated string
    if len(file_ids) == 0 or len(file_ids) > 10:
        logger.error('file_ids list is empty or contains more than 10 IDs')
        return func.HttpResponse(
            "file_ids list is empty or contains more than 10 IDs.",
            status_code=400
        )

    try:
        # Decode JWT to extract the email
        token = auth_header.split(" ")[1]
        decoded_token = jwt.decode(token, options={"verify_signature": False})
        upn = decoded_token['upn']
        user_email = get_user_mapping(upn)
        logger.info(f'User email extracted: {user_email}')

        config = JWTAuth.from_settings_file('jwt_config.json')
        sdk = Client(config)
        logger.info('Authenticated with Box API')

        # Use the user email to get the user ID
        users = sdk.users(filter_term=user_email)
        user = next(users)
        user_id = user.id
        logger.info(f'User ID obtained: {user_id}')

        openai_file_responses = []
        for file_id in file_ids:
            # Perform as_user call to get the file representation
            my_file = sdk.as_user(user).file(file_id).get()
            file_url = my_file.get_download_url()
            openai_file_responses.append(file_url)
        
        response_body = json.dumps({'openaiFileResponse': openai_file_responses})

        return func.HttpResponse(
            response_body,
            status_code=200,
            mimetype="application/json"
        )

    except Exception as e:
        return func.HttpResponse(
            f"An error occurred: {str(e)}",
            status_code=500
        )
    
def get_user_mapping(upn):
    # In our case, the user's authentication email into Azure AD is the same as their email in Box
    # If that is not the case, map the email in Box to the email in Azure AD
    return upn

jwt_config.json.sample

{
    "boxAppSettings": {
      "clientID": "12345",
      "clientSecret": "abcde",
      "appAuth": {
        "publicKeyID": "123",
        "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nvwxyz==\n-----END ENCRYPTED PRIVATE KEY-----\n",
        "passphrase": "lmnop"
      }
    },
    "enterpriseID": "09876"
  }

requirements.txt

boxsdk[jwt]
azure-functions
requests
pyjwt

请务必按照 Azure 指南的其余部分进行后身份验证步骤和 chatGPT 配置:Azure Cookbook 指南

  • Schema 调用了错误的项目或数据集: 如果 ChatGPT 调用了错误的项目或数据集,请考虑更新您的指令,使其更明确 (a) 应调用哪个项目/数据集,或 (b) 要求用户在运行查询之前提供这些确切的详细信息
  • Box 可以在事件流中返回大量数据,这可能会导致错误,

您希望我们优先考虑哪些集成?我们的集成中是否存在错误?在我们的 github 中提交 PR 或 issue,我们会查看。