본문 바로가기
프로그래밍/AI

Chat Plugins - Example

by 사악신 2024. 1. 12.

플러그인을 구축하기 시작하기 위해, 다양한 인증 스키마와 사용 사례를 다루는 간단한 플러그인 세트를 제공하고 있습니다. 인증이 필요 없는 간단한 할 일 목록 플러그인부터 더 강력한 검색 플러그인에 이르기까지, 이 예시들은 플러그인으로 가능하게 하고자 하는 것을 엿볼 수 있게 해줍니다.

개발 중에는 GitHub Codespaces, Replit, 또는 CodeSandbox와 같은 클라우드 개발 환경을 통해 플러그인을 실행할 수 있습니다.

 

Plugin quickstart

플러그인 퀵스타트는 개발자들이 5분 이내에 플러그인을 설정하고 실행할 수 있는 시작점으로 만들어졌습니다. 아직 플러그인을 실행해보지 않았고 하나를 실행하는 데 필요한 최소한의 단계에 익숙해지고 싶다면, 플러그인 퀵스타트 저장소로 시작하는 것을 고려해보세요.

 

Learn how to build a simple todo list plugin with no auth

시작하려면, 먼저 인증이 필요 없는 페이지를 확인한 다음, 다음 필드를 포함하는 ai-plugin.json 파일을 정의하세요:

 

{
    "schema_version": "v1",
    "name_for_human": "TODO List (No Auth)",
    "name_for_model": "todo",
    "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.",
    "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
    "auth": {
        "type": "none"
    },
    "api": {
        "type": "openapi",
        "url": "PLUGIN_HOSTNAME/openapi.yaml"
    },
    "logo_url": "PLUGIN_HOSTNAME/logo.png",
    "contact_email": "support@example.com",
    "legal_info_url": "https://example.com/legal"
}

 

PLUGIN_HOSTNAME은 실제 플러그인 서버의 호스트 이름이어야 한다는 점에 유의하세요.

다음으로, 특정 사용자를 위해 할 일 목록 항목을 생성, 삭제 및 가져오는 API 엔드포인트를 정의할 수 있습니다.

 

import json

import quart
import quart_cors
from quart import request

app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")

_TODOS = {}


@app.post("/todos/<string:username>")
async def add_todo(username):
    request = await quart.request.get_json(force=True)
    if username not in _TODOS:
        _TODOS[username] = []
    _TODOS[username].append(request["todo"])
    return quart.Response(response='OK', status=200)


@app.get("/todos/<string:username>")
async def get_todos(username):
    return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200)


@app.delete("/todos/<string:username>")
async def delete_todo(username):
    request = await quart.request.get_json(force=True)
    todo_idx = request["todo_idx"]
    if 0 <= todo_idx < len(_TODOS[username]):
        _TODOS[username].pop(todo_idx)
    return quart.Response(response='OK', status=200)


@app.get("/logo.png")
async def plugin_logo():
    filename = 'logo.png'
    return await quart.send_file(filename, mimetype='image/png')


@app.get("/.well-known/ai-plugin.json")
async def plugin_manifest():
    host = request.headers['Host']
    with open("ai-plugin.json") as f:
        text = f.read()
        # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the manifest
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/json")


@app.get("/openapi.yaml")
async def openapi_spec():
    host = request.headers['Host']
    with open("openapi.yaml") as f:
        text = f.read()
        # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the OpenAPI spec
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/yaml")


def main():
    app.run(debug=True, host="0.0.0.0", port=5002)


if __name__ == "__main__":
    main()

 

마지막으로, 원격 서버에 정의된 엔드포인트와 일치하도록 OpenAPI 사양을 설정하고 정의해야 합니다. 사양을 통해 API의 전체 기능을 노출할 필요는 없으며, 대신 ChatGPT가 특정 기능에만 접근하도록 선택할 수 있습니다.

또한 서버 정의 코드를 OpenAPI 사양으로 자동 변환하는 많은 도구들이 있어 수동으로 작업할 필요가 없습니다. 위의 Python 코드의 경우, OpenAPI 사양은 다음과 같이 보일 것입니다:

 

openapi: 3.0.1
info:
    title: TODO Plugin
    description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
    version: "v1"
servers:
    - url: PLUGIN_HOSTNAME
paths:
    /todos/{username}:
        get:
            operationId: getTodos
            summary: Get the list of todos
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/getTodosResponse"
        post:
            operationId: addTodo
            summary: Add a todo to the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/addTodoRequest"
            responses:
                "200":
                    description: OK
        delete:
            operationId: deleteTodo
            summary: Delete a todo from the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/deleteTodoRequest"
            responses:
                "200":
                    description: OK

components:
    schemas:
        getTodosResponse:
            type: object
            properties:
                todos:
                    type: array
                    items:
                        type: string
                    description: The list of todos.
        addTodoRequest:
            type: object
            required:
                - todo
            properties:
                todo:
                    type: string
                    description: The todo to add to the list.
                    required: true
        deleteTodoRequest:
            type: object
            required:
                - todo_idx
            properties:
                todo_idx:
                    type: integer
                    description: The index of the todo to delete.
                    required: true

 

Learn how to build a simple todo list plugin with service level auth

시작하려면 서비스 레벨 인증 페이지를 확인한 다음, 다음 필드를 포함하는 ai-plugin.json 파일을 정의하세요:

 

{
    "schema_version": "v1",
    "name_for_human": "TODO List (service auth)",
    "name_for_model": "todo",
    "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.",
    "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
    "auth": {
        "type": "service_http",
        "authorization_type": "bearer",
        "verification_tokens": {
            "openai": "Replace_this_string_with_the_verification_token_generated_in_the_ChatGPT_UI"
        }
    },
    "api": {
        "type": "openapi",
        "url": "https://example.com/openapi.yaml"
    },
    "logo_url": "https://example.com/logo.png",
    "contact_email": "support@example.com",
    "legal_info_url": "https://example.com/legal"
}

 

서비스 레벨 인증 플러그인의 경우 검증 토큰이 필요하다는 점에 유의하세요. 이 토큰은 ChatGPT 웹 UI에서 플러그인 설치 과정 중에 서비스 액세스 토큰을 설정한 후 생성됩니다.

또한 "Example.com"을 여러분의 원격 서버 이름으로 업데이트해야 합니다.

다음으로, 특정 사용자를 위해 할 일 목록 항목을 생성, 삭제 및 가져오는 API 엔드포인트를 정의할 수 있습니다. 이 엔드포인트들은 사용자가 인증되었는지도 확인합니다.

 

import json

import quart
import quart_cors
from quart import request

app = quart_cors.cors(quart.Quart(__name__))

# This key can be anything, though you will likely want a randomly generated sequence.
_SERVICE_AUTH_KEY = "REPLACE_ME"
_TODOS = {}

def assert_auth_header(req):
    assert req.headers.get(
        "Authorization", None) == f"Bearer {_SERVICE_AUTH_KEY}"

@app.post("/todos/<string:username>")
async def add_todo(username):
    assert_auth_header(quart.request)
    request = await quart.request.get_json(force=True)
    if username not in _TODOS:
        _TODOS[username] = []
    _TODOS[username].append(request["todo"])
    return quart.Response(response='OK', status=200)

@app.get("/todos/<string:username>")
async def get_todos(username):
    assert_auth_header(quart.request)
    return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200)

@app.delete("/todos/<string:username>")
async def delete_todo(username):
    assert_auth_header(quart.request)
    request = await quart.request.get_json(force=True)
    todo_idx = request["todo_idx"]
    if 0 <= todo_idx < len(_TODOS[username]):
        _TODOS[username].pop(todo_idx)
    return quart.Response(response='OK', status=200)

@app.get("/logo.png")
async def plugin_logo():
    filename = 'logo.png'
    return await quart.send_file(filename, mimetype='image/png')

@app.get("/.well-known/ai-plugin.json")
async def plugin_manifest():
    host = request.headers['Host']
    with open("ai-plugin.json") as f:
        text = f.read()
        return quart.Response(text, mimetype="text/json")

@app.get("/openapi.yaml")
async def openapi_spec():
    host = request.headers['Host']
    with open("openapi.yaml") as f:
        text = f.read()
        return quart.Response(text, mimetype="text/yaml")

def main():
    app.run(debug=True, host="0.0.0.0", port=5002)

if __name__ == "__main__":
    main()

 

마지막으로, 원격 서버에 정의된 엔드포인트와 일치하도록 OpenAPI 사양을 설정하고 정의해야 합니다. 일반적으로, 인증 방법에 관계없이 OpenAPI 사양은 동일한 모습을 보일 것입니다. 자동 OpenAPI 생성기를 사용하면 OpenAPI 사양을 생성할 때 오류의 가능성을 줄일 수 있습니다.

 

openapi: 3.0.1
info:
    title: TODO Plugin
    description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
    version: "v1"
servers:
    - url: https://example.com
paths:
    /todos/{username}:
        get:
            operationId: getTodos
            summary: Get the list of todos
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/getTodosResponse"
        post:
            operationId: addTodo
            summary: Add a todo to the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/addTodoRequest"
            responses:
                "200":
                    description: OK
        delete:
            operationId: deleteTodo
            summary: Delete a todo from the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/deleteTodoRequest"
            responses:
                "200":
                    description: OK

components:
    schemas:
        getTodosResponse:
            type: object
            properties:
                todos:
                    type: array
                    items:
                        type: string
                    description: The list of todos.
        addTodoRequest:
            type: object
            required:
                - todo
            properties:
                todo:
                    type: string
                    description: The todo to add to the list.
                    required: true
        deleteTodoRequest:
            type: object
            required:
                - todo_idx
            properties:
                todo_idx:
                    type: integer
                    description: The index of the todo to delete.
                    required: true

 

Learn how to build a simple sports stats plugin

이 플러그인은 간단한 스포츠 통계 API의 예입니다. 무엇을 구축할지 고려할 때, 도메인 정책과 사용 정책을 염두에 두세요.

시작하려면, 다음 필드를 포함하는 ai-plugin.json 파일을 정의하세요:

 

{
    "schema_version": "v1",
    "name_for_human": "Sport Stats",
    "name_for_model": "sportStats",
    "description_for_human": "Get current and historical stats for sport players and games.",
    "description_for_model": "Get current and historical stats for sport players and games. Always display results using markdown tables.",
    "auth": {
        "type": "none"
    },
    "api": {
        "type": "openapi",
        "url": "PLUGIN_HOSTNAME/openapi.yaml"
    },
    "logo_url": "PLUGIN_HOSTNAME/logo.png",
    "contact_email": "support@example.com",
    "legal_info_url": "https://example.com/legal"
}

 

PLUGIN_HOSTNAME은 실제 플러그인 서버의 호스트 이름이어야 한다는 점을 유의하세요.

다음으로, 간단한 스포츠 서비스 플러그인을 위한 모의 API를 정의합니다.

 

import json
import requests
import urllib.parse

import quart
import quart_cors
from quart import request

app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")
HOST_URL = "https://example.com"

@app.get("/players")
async def get_players():
    query = request.args.get("query")
    res = requests.get(
        f"{HOST_URL}/api/v1/players?search={query}&page=0&per_page=100")
    body = res.json()
    return quart.Response(response=json.dumps(body), status=200)


@app.get("/teams")
async def get_teams():
    res = requests.get(
        "{HOST_URL}/api/v1/teams?page=0&per_page=100")
    body = res.json()
    return quart.Response(response=json.dumps(body), status=200)


@app.get("/games")
async def get_games():
    query_params = [("page", "0")]
    limit = request.args.get("limit")
    query_params.append(("per_page", limit or "100"))
    start_date = request.args.get("start_date")
    if start_date:
        query_params.append(("start_date", start_date))
    end_date = request.args.get("end_date")

    if end_date:
        query_params.append(("end_date", end_date))
    seasons = request.args.getlist("seasons")

    for season in seasons:
        query_params.append(("seasons[]", str(season)))
    team_ids = request.args.getlist("team_ids")

    for team_id in team_ids:
        query_params.append(("team_ids[]", str(team_id)))

    res = requests.get(
        f"{HOST_URL}/api/v1/games?{urllib.parse.urlencode(query_params)}")
    body = res.json()
    return quart.Response(response=json.dumps(body), status=200)


@app.get("/stats")
async def get_stats():
    query_params = [("page", "0")]
    limit = request.args.get("limit")
    query_params.append(("per_page", limit or "100"))
    start_date = request.args.get("start_date")
    if start_date:
        query_params.append(("start_date", start_date))
    end_date = request.args.get("end_date")

    if end_date:
        query_params.append(("end_date", end_date))
    player_ids = request.args.getlist("player_ids")

    for player_id in player_ids:
        query_params.append(("player_ids[]", str(player_id)))
    game_ids = request.args.getlist("game_ids")

    for game_id in game_ids:
        query_params.append(("game_ids[]", str(game_id)))
    res = requests.get(
        f"{HOST_URL}/api/v1/stats?{urllib.parse.urlencode(query_params)}")
    body = res.json()
    return quart.Response(response=json.dumps(body), status=200)


@app.get("/season_averages")
async def get_season_averages():
    query_params = []
    season = request.args.get("season")
    if season:
        query_params.append(("season", str(season)))
    player_ids = request.args.getlist("player_ids")

    for player_id in player_ids:
        query_params.append(("player_ids[]", str(player_id)))
    res = requests.get(
        f"{HOST_URL}/api/v1/season_averages?{urllib.parse.urlencode(query_params)}")
    body = res.json()
    return quart.Response(response=json.dumps(body), status=200)


@app.get("/logo.png")
async def plugin_logo():
    filename = 'logo.png'
    return await quart.send_file(filename, mimetype='image/png')


@app.get("/.well-known/ai-plugin.json")
async def plugin_manifest():
    host = request.headers['Host']
    with open("ai-plugin.json") as f:
        text = f.read()
        # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the manifest
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/json")


@app.get("/openapi.yaml")
async def openapi_spec():
    host = request.headers['Host']
    with open("openapi.yaml") as f:
        text = f.read()
        # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the OpenAPI spec
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/yaml")


def main():
    app.run(debug=True, host="0.0.0.0", port=5001)


if __name__ == "__main__":
    main()

 

마지막으로, OpenAPI 사양을 정의합니다:

openapi: 3.0.1
info:
    title: Sport Stats
    description: Get current and historical stats for sport players and games.
    version: "v1"
servers:
    - url: PLUGIN_HOSTNAME
paths:
    /players:
        get:
            operationId: getPlayers
            summary: Retrieves all players from all seasons whose names match the query string.
            parameters:
                - in: query
                  name: query
                  schema:
                      type: string
                  description: Used to filter players based on their name. For example, ?query=davis will return players that have 'davis' in their first or last name.
            responses:
                "200":
                    description: OK
    /teams:
        get:
            operationId: getTeams
            summary: Retrieves all teams for the current season.
            responses:
                "200":
                    description: OK
    /games:
        get:
            operationId: getGames
            summary: Retrieves all games that match the filters specified by the args. Display results using markdown tables.
            parameters:
                - in: query
                  name: limit
                  schema:
                      type: string
                  description: The max number of results to return.
                - in: query
                  name: seasons
                  schema:
                      type: array
                      items:
                          type: string
                  description: Filter by seasons. Seasons are represented by the year they began. For example, 2018 represents season 2018-2019.
                - in: query
                  name: team_ids
                  schema:
                      type: array
                      items:
                          type: string
                  description: Filter by team ids. Team ids can be determined using the getTeams function.
                - in: query
                  name: start_date
                  schema:
                      type: string
                  description: A single date in 'YYYY-MM-DD' format. This is used to select games that occur on or after this date.
                - in: query
                  name: end_date
                  schema:
                      type: string
                  description: A single date in 'YYYY-MM-DD' format. This is used to select games that occur on or before this date.
            responses:
                "200":
                    description: OK
    /stats:
        get:
            operationId: getStats
            summary: Retrieves stats that match the filters specified by the args. Display results using markdown tables.
            parameters:
                - in: query
                  name: limit
                  schema:
                      type: string
                  description: The max number of results to return.
                - in: query
                  name: player_ids
                  schema:
                      type: array
                      items:
                          type: string
                  description: Filter by player ids. Player ids can be determined using the getPlayers function.
                - in: query
                  name: game_ids
                  schema:
                      type: array
                      items:
                          type: string
                  description: Filter by game ids. Game ids can be determined using the getGames function.
                - in: query
                  name: start_date
                  schema:
                      type: string
                  description: A single date in 'YYYY-MM-DD' format. This is used to select games that occur on or after this date.
                - in: query
                  name: end_date
                  schema:
                      type: string
                  description: A single date in 'YYYY-MM-DD' format. This is used to select games that occur on or before this date.
            responses:
                "200":
                    description: OK
    /season_averages:
        get:
            operationId: getSeasonAverages
            summary: Retrieves regular season averages for the given players. Display results using markdown tables.
            parameters:
                - in: query
                  name: season
                  schema:
                      type: string
                  description: Defaults to the current season. A season is represented by the year it began. For example, 2018 represents season 2018-2019.
                - in: query
                  name: player_ids
                  schema:
                      type: array
                      items:
                          type: string
                  description: Filter by player ids. Player ids can be determined using the getPlayers function.
            responses:
                "200":
                    description: OK

 

Learn how to build a simple OAuth todo list plugin

다음으로, OAuth 서비스를 정의해야 합니다. 이 OAuth 예제는 실제 생산 환경에서의 사용을 위한 것이 아니라, 간단한 OAuth 흐름이 어떻게 보이는지를 강조하여 개발자들이 실제 생산 솔루션을 구축하는 경험을 얻을 수 있도록 하는 것을 목적으로 합니다.

{
    "schema_version": "v1",
    "name_for_human": "TODO List (OAuth)",
    "name_for_model": "todo_oauth",
    "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.",
    "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
    "auth": {
        "type": "oauth",
        "client_url": "PLUGIN_HOSTNAME/oauth",
        "scope": "",
        "authorization_url": "PLUGIN_HOSTNAME/auth/oauth_exchange",
        "authorization_content_type": "application/json",
        "verification_tokens": {
            "openai": "Replace_this_string_with_the_verification_token_generated_in_the_ChatGPT_UI"
        }
    },
    "api": {
        "type": "openapi",
        "url": "PLUGIN_HOSTNAME/openapi.yaml"
    },
    "logo_url": "PLUGIN_HOSTNAME/logo.png",
    "contact_email": "contact@example.com",
    "legal_info_url": "http://www.example.com/legal"
}

 

 

import json

import quart
import quart_cors
from quart import request

app = quart_cors.cors(quart.Quart(__name__), allow_origin="*")

_TODOS = {}

@app.post("/todos/<string:username>")
async def add_todo(username):
    request = await quart.request.get_json(force=True)
    if username not in _TODOS:
        _TODOS[username] = []
    _TODOS[username].append(request["todo"])
    return quart.Response(response='OK', status=200)

@app.get("/todos/<string:username>")
async def get_todos(username):
    print(request.headers)
    return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200)

@app.delete("/todos/<string:username>")
async def delete_todo(username):
    request = await quart.request.get_json(force=True)
    todo_idx = request["todo_idx"]
    # fail silently, it's a simple plugin
    if 0 <= todo_idx < len(_TODOS[username]):
        _TODOS[username].pop(todo_idx)
    return quart.Response(response='OK', status=200)

@app.get("/logo.png")
async def plugin_logo():
    filename = 'logo.png'
    return await quart.send_file(filename, mimetype='image/png')

@app.get("/.well-known/ai-plugin.json")
async def plugin_manifest():
    host = request.headers['Host']
    with open("manifest.json") as f:
        text = f.read()
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/json")

@app.get("/openapi.yaml")
async def openapi_spec():
    host = request.headers['Host']
    with open("openapi.yaml") as f:
        text = f.read()
        text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
        return quart.Response(text, mimetype="text/yaml")

@app.get("/oauth")
async def oauth():
    query_string = request.query_string.decode('utf-8')
    parts = query_string.split('&')
    kvps = {}
    for part in parts:
        k, v = part.split('=')
        v = v.replace("%2F", "/").replace("%3A", ":")
        kvps[k] = v
    print("OAuth key value pairs from the ChatGPT Request: ", kvps)
    url = kvps["redirect_uri"] + f"?code={OPENAI_CODE}"
    print("URL: ", url)
    return quart.Response(
        f'<a href="{url}">Click to authorize</a>'
    )

# Sample names
OPENAI_CLIENT_ID = "id"
OPENAI_CLIENT_SECRET = "secret"
OPENAI_CODE = "abc123"
OPENAI_TOKEN = "def456"

@app.post("/auth/oauth_exchange")
async def oauth_exchange():
    request = await quart.request.get_json(force=True)
    print(f"oauth_exchange {request=}")

    if request["client_id"] != OPENAI_CLIENT_ID:
        raise RuntimeError("bad client ID")
    if request["client_secret"] != OPENAI_CLIENT_SECRET:
        raise RuntimeError("bad client secret")
    if request["code"] != OPENAI_CODE:
        raise RuntimeError("bad code")

    return {
        "access_token": OPENAI_TOKEN,
        "token_type": "bearer"
    }

def main():
    app.run(debug=True, host="0.0.0.0", port=5002)

if __name__ == "__main__":
    main()

 

마지막으로, 다른 예제들과 마찬가지로, 엔드포인트를 기반으로 간단한 OpenAPI 파일을 정의합니다:

openapi: 3.0.1
info:
    title: TODO Plugin
    description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
    version: "v1"
servers:
    - url: PLUGIN_HOSTNAME
paths:
    /todos/{username}:
        get:
            operationId: getTodos
            summary: Get the list of todos
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/getTodosResponse"
        post:
            operationId: addTodo
            summary: Add a todo to the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/addTodoRequest"
            responses:
                "200":
                    description: OK
        delete:
            operationId: deleteTodo
            summary: Delete a todo from the list
            parameters:
                - in: path
                  name: username
                  schema:
                      type: string
                  required: true
                  description: The name of the user.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/deleteTodoRequest"
            responses:
                "200":
                    description: OK

components:
    schemas:
        getTodosResponse:
            type: object
            properties:
                todos:
                    type: array
                    items:
                        type: string
                    description: The list of todos.
        addTodoRequest:
            type: object
            required:
                - todo
            properties:
                todo:
                    type: string
                    description: The todo to add to the list.
                    required: true
        deleteTodoRequest:
            type: object
            required:
                - todo_idx
            properties:
                todo_idx:
                    type: integer
                    description: The index of the todo to delete.
                    required: true

 

Learn how to build a semantic search and retrieval plugin

ChatGPT 검색 플러그인은 보다 완성도 있는 코드 예제입니다. 플러그인의 범위가 넓기 때문에, 보다 고급 플러그인이 어떻게 생겼는지 확인하기 위해 코드를 자세히 읽어보는 것이 좋습니다.

검색 플러그인에는 다음이 포함됩니다:

  • 다양한 벡터 데이터베이스 제공자 지원
  • 4가지 다른 인증 방법
  • 다양한 API 기능

 

반응형

'프로그래밍 > AI' 카테고리의 다른 글

Chat Plugins - productionizing your plugin  (0) 2024.01.12
Chat Plugins - plugin authentication  (0) 2024.01.12
Chat Plugins - Get started  (0) 2024.01.12
Chat Plugins  (2) 2024.01.11
Actions in GPTs  (0) 2024.01.11

댓글