Создайте веб-приложение на основе ChatGPT с помощью Plotly Dash.

API ChatGPT наконец-то здесь

Chat-Generative Pre-trained Transformer (ChatGPT) от OpenAI был одним из самых прорывных проектов искусственного интеллекта с момента его бета-тестирования в ноябре 2022 года. Нравится вам это или нет, в течение двух месяцев после запуска ChatGPT достиг более 100 миллионов пользователей. », что делает его самым быстрорастущим потребительским приложением на сегодняшний день. Как и многие энтузиасты обработки естественного языка (NLP), я терпеливо ждал, когда модель станет доступна через API OpenAI.

Ну вот, наконец, настал этот день! 1 марта 2023 года OpenAI объявила, что модель ChatGPT наконец-то доступна для разработчиков.

В этом руководстве мы рассмотрим, как получить доступ к модели ChatGPT с помощью API OpenAI, и создадим простое приложение Write Assistant с использованием Dash и Python, чтобы изучить возможности быстрой разработки.

Мы рассмотрим следующее:

  • Что такое ChatGPT?
  • Как получить доступ к ChatGPT API
  • Как использовать API ChatGPT с Python
  • Как настроить вызовы API ChatGPT для достижения лучших результатов
  • Что такое Плотли Дэш?
  • Как создать приложение Dash
  • Как создать приложение помощника по письму ChatGPT

Найдите полный код в конце статьи!

Что такое ChatGPT?

По своей сути ChatGPT представляет собой мощную модель большого языка (LLM), предназначенную для понимания и использования человеческого языка в разговоре. Это означает, что вы вводите приглашение, и он выводит сгенерированный ответ на основе приглашения. Хотя результат может быть довольно хорошим, во многих случаях даже соперничающим с человеческим качеством, появилось множество примеров того, как ChatGPT выдает фактически и/или этически неверные ответы на вопросы, поскольку все больше и больше людей взламывают его.

Помимо двусторонних разговоров, он может помочь редактировать текст для проверки грамматики, выполнять анализ настроений и извлекать темы, писать стихи, песни и эссе и даже писать компьютерный код на таких языках, как Python, SQL и JavaScript. Что касается того, что он может ответить, он действительно динамичен и мощен. Чтобы узнать больше о том, как работает ChatGPT, посетите блог OpenAI:



Для приложения для письма мы создадим пользовательский интерфейс, используя библиотеку Dash, которая позволит нам отправить приглашение в модель ChatGPT и получить результат.

Как получить доступ к ChatGPT API

Перед доступом к инструментам разработчика ChatGPT нам необходимо сгенерировать ключ интерфейса прикладного программирования (API). Ключ API — это код, используемый для аутентификации нашей учетной записи пользователя с помощью инструментов разработчика. Чтобы сгенерировать ключ API и получить доступ к API ChatGPT, зарегистрируйте учетную запись пользователя OpenAI.

Языковые модели OpenAI

OpenAI сделал доступным несколько языковых моделей, некоторые из которых более мощные, чем другие. Их последняя модель gpt-3.5-turbo — это то, что использует ChatGPT, поэтому мы будем использовать ее в этом руководстве. Для получения полного списка моделей ознакомьтесь с документацией по моделям OpenAI.

Цены на API OpenAI

К сожалению, модель не является открытой. Хотя это относительно недорого, разработка с использованием модели gpt-3.5-turbo (ChatGPT) связана с затратами. OpenAI взимает плату за токен по ставке 0,002 доллара США за 1000 токенов. OpenAI говорит, что 1000 токенов обычно составляют около 750 слов. Для модели ChatGPT максимальное количество токенов, которые можно использовать одновременно, составляет 4096, включая входные и выходные токены. Например, если ваш вызов API использует 10 токенов во вводе сообщения, а вы получаете 20 токенов в выводе сообщения, вам будет выставлен счет за 30 токенов.

Создание ключа API

После настройки учетной записи и платежной информации создайте ключ API, развернув учетную запись и выбрав Просмотреть ключи API. На странице ключей API отобразится:

Нажмите кнопку «Создать новый секретный ключ», чтобы создать новый ключ API. Как только он будет сгенерирован, скопируйте его и сохраните в надежном месте. Вы не можете снова получить к нему доступ!

Генерация ключа API бесплатна, поэтому вы можете генерировать многие из них по мере необходимости. Теперь, когда у нас есть ключ API, мы можем начать программировать!

Управляйте своими ключами API

Никогда не кодируйте ключ API в своем приложении и не делитесь им с другими. Если вы новичок в управлении своими ключами, обязательно сохраните их в надежном месте. В приведенных ниже примерах кода я импортирую свой ключ из файла .py.

Ключи API могут быть очень ценными и должны быть защищены, поскольку их использование может стоить денег. Если вы храните ключ в файле .py, добавьте этот файл в свой файл gitignore, чтобы предотвратить его передачу в репозиторий!

Что касается политики хранения данных OpenAI:

Перед использованием их инструментов разработчика стоит ознакомиться с Политикой использования полных данных OpenAI. Как правило, они будут хранить данные API в течение 30 дней. Однако, что касается данных, отправленных через API:

По умолчанию OpenAI не будет использовать данные, отправленные клиентами через наш API, для обучения моделей OpenAI или улучшения предложения услуг OpenAI. Данные, предоставленные пользователем для тонкой настройки, будут использоваться только для тонкой настройки модели клиента. Однако OpenAI позволит пользователям делиться своими данными, чтобы улучшить производительность модели.

Как использовать API ChatGPT с Python

Благодаря библиотеке openai Python OpenAI сделал свой API очень доступным и простым в использовании. Всего несколькими строками кода мы можем подключиться к API, отправить запрос модели ChatGPT и получить ответ.

Используя pip, установите библиотеку openai Python. Если у вас уже установлен openai, обновите его, чтобы получить доступ к конечной точке ChatCompletion.

pip install openai
OR 
pip install --upgrade openai

Чтобы начать изучение API, давайте импортируем зависимости и загрузим ключ API.

#import the openAI python library
import openai
#import the api key from the .py file
from openaikey import apikey

# Load your API key from the variable
openai.api_key = apikey

Далее давайте создадим вызов API к конечной точке ChatCompletion и передадим простое сообщение в модель в качестве теста. Для вызова API есть два обязательных параметра:

  • model — ID модели, которую мы хотим использовать (gpt-3.5-turbo).
  • messages — Массив сообщений для отправки модели.
#call the ChatCompletion end
response = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=[{"role": "user", "content": "Hello!"}]
)

response

Вызов API вернет сгенерированное моделью сообщение в качестве вывода, сохраненное в переменной response .

Обратите внимание, что в параметре messages мы передаем массив объектов, содержащих ключ role и ключ content. Значение role может быть «системным», «пользователем» или «помощником», а значение содержимого — это просто содержимое сообщения. Когда модели предлагается вести себя определенным образом, разговор обычно начинается с системного сообщения, за которым следуют чередующиеся сообщения пользователя и помощника. Например, если мы хотим, чтобы модель помогла нам написать эссе, мы можем создать messagesполезную нагрузку следующим образом:

messages = [
  {"role": "system", "content": "You are a helpful assistant designed to write academic essays."},
  {"role": "user", "content": "Write an outline for an academic essay in 500 words or less"},
  {"role": "assistant", "content": "On what topic?"},
  {"role": "user", "content": "Army Ants"}
 ]

Значение systemcontent помогает задать поведение помощника. Значение usercontent помогает проинструктировать помощника. Значение assistantcontent помогает сохранять предыдущие ответы. Как мы видим, роли и контент могут быть написаны разработчиком, чтобы дать модели примеры желаемого поведения.

Просмотр объекта ответа

В дополнение к сообщению, сгенерированному моделью, ответ содержит некоторую полезную информацию. Вот пример объекта OpenAI, который возвращается из вызова API:

<OpenAIObject chat.completion id=chatcmpl-6qZ at 0x155bfb68> 
JSON: {
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "\n\nHello there, how may I assist you today?",
        "role": "assistant"
      }
    }
  ],
  "created": 1677987572,
  "id": "chatcmpl-6qZ",
  "model": "gpt-3.5-turbo-0301",
  "object": "chat.completion",
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

Обратите внимание, что объект message содержит пары ключ:значение содержимого и роли. roleвозвращающий ответ, сгенерированный моделью, является «помощником». Ответ также содержит отметку времени эпохи UNIX в качестве значения для ключа created и дает нам общее количество токенов, используемых вызовом API, чтобы мы могли управлять расходами на вызовы API.

Если мы просто хотим извлечь сообщение из ответа, мы можем сослаться на объект message внутри объекта OpenAI следующим образом:

response['choices'][0]['message']['content']

Как настроить вызовы API ChatGPT для достижения лучших результатов

При создании вызова API к конечной точке ChatCompletion мы можем передать дополнительные параметры, которые повлияют на качество ответа, сгенерированного моделью.

  • Temperature — Устанавливает температуру дискретизации для разнесения на выходе. По умолчанию 1 и может быть установлено от 0 до 2. Более высокие значения делают вывод более случайным, в то время как более низкие значения делают результаты более детерминированными и повторяющимися. OpenAI рекомендует изменять либо top_p, либо температуру, но не то и другое одновременно.
  • Top_P — Устанавливает выборку ядра для выходного разнесения и является методом выборки, альтернативным температуре. По умолчанию 1 и может быть установлено от 0 до 1. OpenAI рекомендует изменить либо top_p, либо temperature, но не оба.
  • Presence_penalty — устанавливает, насколько штрафовать новые токены в зависимости от того, появляются ли они в тексте до сих пор, чтобы увеличить вероятность того, что сгенерированный текст состоит из нескольких тем. По умолчанию 0 и может быть установлено от 0 до 2.
  • Frequency_penalty — устанавливает, насколько штрафовать новые токены в зависимости от их частоты в текущем тексте, чтобы уменьшить вероятность повторения сгенерированного текста. По умолчанию 0 и может быть установлено от 0 до 2.
  • Max_tokens — максимальное количество токенов, которое может быть сгенерировано за ответ. Значение по умолчанию — 4096.

Помещение этих значений в вызов API выглядит следующим образом:

response = openai.ChatCompletion.create(
  model="gpt-3.5-turbo",
  messages=messages,
  temperature = 0.8,
  top_p = 1, 
  presence_penalty = 0.1,
  frequency_penalty = 0.4,
  max_tokens = 10
)

Теперь, когда мы знаем, как получить ключ API, выполнить вызов API к модели ChatGPT и настроить параметры вызова API, пришло время создать пользовательский интерфейс и выполнить небольшую оперативную разработку, чтобы управлять выводом нашего помощника по письму.

Что такое Плотли Дэш?

Dash by Plotly — это мощная платформа с открытым исходным кодом для Python, написанная поверх Flask, Plotly.js и React.js. Он абстрагирует сложности этих технологий, превращая их в простые в применении компоненты. Я представлю краткий обзор основ, но если вы новичок в библиотеке Dash или хотите подробно изучить все функции, ознакомьтесь с моим руководством для начинающих или веб-сайтом pythondashboards.com:



Dash имеет растущее сообщество, наполненное увлеченными разработчиками и создателями. Поскольку фреймворк имеет открытый исходный код, сообщество разработало несколько действительно крутых компонентов, которые можно интегрировать в любое приложение Dash.

Установите Dash с помощью pip:

pip install dash

Как создать приложение Dash

С Dash вам не нужно писать HTML или CSS с нуля, хотя понимание основ каждого из них определенно помогает, когда дело доходит до дизайна пользовательского интерфейса (UI).

Приложения Dash в основном состоят из двух частей:

1. Макет

2. Обратные вызовы

Макет тире

Макет состоит из дерева компонентов, которые описывают, как выглядит приложение и как пользователи взаимодействуют с контентом. Dash поставляется с несколькими библиотеками компонентов, такими как dash_core_components, dash_html_components и Dash DataTable.

В библиотеке dash_html_components есть компонент почти для каждого тега HTML. Библиотека dash_core_components включает интерактивные компоненты более высокого уровня, такие как средства выбора даты, контрольные списки, поля ввода, графики и раскрывающиеся списки. Полный список библиотек основных компонентов см. в документации.

Компоненты начальной загрузки Dash

В дополнение к основным библиотекам Dash я использую библиотеку Dash Bootstrap Component, чтобы упростить отзывчивый дизайн веб-сайта. Подобно тому, как библиотека компонентов Dash HTML позволяет применять HTML с помощью Python, библиотека компонентов CSS Dash Bootstrap позволяет добавлять внешние компоненты Bootstrap, на которые влияет CSS-фреймворк Bootstrap. Узнайте больше о компонентах Bootstrap в моем руководстве для начинающих.

Установите библиотеку компонентов Dash Bootstrap с помощью pip:

pip install dash-bootstrap-components

Обратные вызовы тире

Обратные вызовы — это то, что поддерживает логику интерактивных приложений Dash. Обратные вызовы — это функции Python, которые автоматически вызываются всякий раз, когда изменяется свойство входного компонента. Например, представьте себе кнопку на веб-сайте. При нажатии за кулисами срабатывает обратный вызов, запускающий функциональность кнопки. Можно связать обратные вызовы в цепочку, что позволяет одному изменению запускать несколько обновлений во всем приложении.

На базовом уровне обратные вызовы состоят из Inputs и Outputs. Они также могут включать State. Функционал работает через app.callback декоратор. Входы и выходы — это просто свойства компонента, с которыми пользователь может взаимодействовать. Например, входным параметром может быть вариант, который вы выбираете из раскрывающегося списка, а выходным может быть визуализация. Скажем, у меня есть список штатов, и когда я выбираю CA, Калифорния выделяется на карте.

Как создать приложение помощника по письму ChatGPT

Получение хороших результатов от модели ChatGPT зависит от быстрой разработки. В нашем приложении помощника по письму давайте создадим несколько разных параметров, которые будут передаваться для запроса системы перед отправкой запроса пользователя. Таким образом мы можем подготовить ChatGPT к выполнению этой задачи.

После выбора системной подсказки пользователь вводит свое сообщение через текстовое поле и может нажать кнопку «Создать ответ», чтобы отправить его модели. Проходя процесс создания приложения, мы сделаем следующее:

  • Создание схемы приложения Dash
  • Создайте компонент system_prompt
  • Создайте компонент output_style
  • Создайте компонент text_area
  • Завершите макет приложения
  • Создайте обратный вызов приложения Dash

Создание схемы приложения Dash

Мы начнем с простого макета приложения после создания экземпляра Dash, а затем добавим в него наши функциональные компоненты. После создания макета мы создадим обратный вызов, который передаст нашу логику API ChatGPT.

Начните с создания файла Python с именем app.py. Здесь мы будем писать приложение. Поскольку это приложение довольно простое, нам понадобится только один файл.

После создания файла импортируйте зависимости и создайте структуру макета приложения Dash, создав экземпляр Dash с темой начальной загрузки.

#import dependencies
from dash import Dash, dcc, html, Input, Output, State, callback_context
import dash_bootstrap_components as dbc
from openaikey import apikey
import pandas as pd
import openai

# Load your API key from an environment variable or secret management service
openai.api_key = apikey


#instantiate dash and set the boostrap theme
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

#TO DO:
#   Create a system prompt function
#   Create a output stype function
#   Create a text prompt field

#create layout
app.layout = html.Div([
    dbc.Container([
   
   ])#end container
  ]) #end div

#TO DO:
#    Create a callback that takes in the system prompt, output style, and text field
#    Return the ChatGPT output


#run app server
if __name__ == '__main__':
    app.run_server(debug=True)

Начните компоновку с компонента html.Div и компонента dbc.Container . Остальные компоненты приложения будут размещены внутри контейнера. Компонент-контейнер использует сетку начальной загрузки, добавляя отзывчивость к разным размерам экрана и предотвращая растягивание компонентов на весь экран.

Создайте компонент system_prompts

Вместо того, чтобы позволить пользователю написать собственное системное приглашение, давайте создадим функцию system_prompts, которая устанавливает компонент заголовка html.H1 и компонент dcc.Dropdown. Выпадающий список предоставит пользователю несколько различных вариантов. Каждый параметр будет соответствовать логике, которая передается в модель ChatGPT, когда пользователь отправляет свое письменное приглашение.

def system_prompts():
    return  html.Div([
             html.H3('Select your writing genre:')
             , dbc.Row([
                dbc.Col(
                    dcc.Dropdown(id = 'sys-prompt', options=['Academic Essay', 'Horror Story', 'Romance Novel']
                    , value='Academic Essay')
                , width=4)#end col 1
              , dbc.Col(
                    html.P('Sets the system level prompt to improve the style of the output.')
                    , width=6) #end col 2          
             ])#end row 
         ])#end div

Обратите внимание, что мы передаем значение id в наш компонент dcc.Dropdown. Компонентам необходимо значение идентификатора для использования в обратных вызовах, и рекомендуется помечать их.

Используя Row и Col из компонентов начальной загрузки, мы можем создать выпадающий список вместе с текстом справки, объясняющим, для чего этот выпадающий список.

Создайте компонент output_style

Аналогично компоненту system_prompts, функция output_style создает раскрывающийся список и некоторый текст справки, который позволит пользователю выбрать, хотят ли они, чтобы ChatGPT возвращал схему, абзац или список.

def output_style():
    return  html.Div([
             html.H3('Select your output style:')
             , dbc.Row([
                dbc.Col(
                    dcc.Dropdown(id = 'output-style', options=['Outline', 'Paragraph', 'List']
                    , value='Outline')
                , width=4)#end col 1
             , dbc.Col(
                    html.P('Sets the style of output returned (outline, paragraph, or list)')
                    , width=6
                    )#end col 2          
             ])#end row 
         ])#end div

Создайте компонент text_area

Нам нужно текстовое поле, в которое пользователь может ввести текст и отправить его модели ChatGPT. Давайте создадим функцию с именем text_area, которая использует dbc.Textarea для создания большого текстового поля. Мы также добавим dbc.Button пользователь может щелкнуть, чтобы отправить текст.

def text_areas():
    return html.Div([ 
            html.H3('Enter your prompt:')
            , dbc.Textarea(id = 'my-input'
                , size="lg"
                , placeholder="Enter your text")
            , dbc.Button("Generate Text"
                , id="gen-button"
                , className="me-2"
                , n_clicks=0)
            ])

Обязательно присвойте dbc.Textarea и dbc.Button значение id, чтобы мы могли ссылаться на них в обратном вызове приложения.

Завершите макет приложения

Теперь, когда у нас есть функции для создания системной подсказки, стиля вывода и текстового поля пользовательской подсказки, мы можем создать макет нашего приложения Dash. В дополнение к нашим функциям добавим заголовок и раздел вывода.

app.layout = html.Div([
        dbc.Container([
            html.H1('ChatGPT Writing Assitant')
            , html.Br()
            , system_prompts()
            , html.Br()
            , output_style()
            , html.Br()
            , text_areas()
            , html.Br()
            , html.H3('Output:')
            , html.Div(id='my-output')
        ]) #end container
  ]) #end div

Обратите внимание, что мы можем использовать html.Br, чтобы добавить разрывы в макете, разделяя компоненты. Без них вещи кажутся сплющенными.

Создайте обратный вызов приложения Dash

Обратный вызов используется для передачи нашей логики в ChatGPT API. Когда пользователь выбирает параметры из наших раскрывающихся компонентов, вводит приглашение и нажимает кнопку «Создать текст», вызов API будет создан и отправлен. Мы проанализируем ответ и выведем текст.

Создайте обратный вызов за пределами app.layout. Обратный вызов использует Output, Input и State. Для каждого из этих параметров требуется component_id и component_property. Свойство — это то, что передается в обратный вызов для запуска логики.

Для нашего sys-prompt component_id нам нужно подумать о системной подсказке для каждого из выбираемых значений. Используйте оператор If/Else, чтобы связать раскрывающийся список с системной подсказкой. Я рекомендую попробовать такую ​​подсказку для «Академического эссе»:

Вы академический профессор мирового класса и технический писатель мирового класса, который хочет создавать последовательные академические эссе. Создавайте контент шаг за шагом.

Для нашего output-style component_id нам нужно отправить подсказку «помощнику». Это приглашение будет содержать конкретные указания, касающиеся формата, установленного ChatGPT. Я рекомендую попробовать это для «наброска»:

Ответить кратким изложением не более 500 слов

После построения операторов If/Else для нашей логики подсказок создайте полезную нагрузку сообщения, которое принимает подсказки в качестве значений:

messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": style},
            {"role": "assistant", "content": "On what topic?"},
            {"role": "user", "content": input_value}
        ]

Завершенный обратный вызов будет выглядеть так:

@app.callback(
    Output(component_id='my-output', component_property='children'),
    Input(component_id='gen-button', component_property='n_clicks'),
    Input(component_id='sys-prompt', component_property='value'),
    Input(component_id='output-style', component_property='value'),
    State(component_id='my-input', component_property='value')    
)
def update_output_div(gen, sp, os, input_value):
    #print(input_value) #debug
    
    #set text to sample
    text = "This is a \nsample"
    
    #listen for button clicks
    changed_id = [p['prop_id'] for p in callback_context.triggered][0]

    #create system prompt logic
    if sp == 'Academic Essay':
        system_prompt = 'You are a world class academic professor and a world class technical writer that wants to produce coherent academic essays. Produce content step by step.'
    elif sp == 'Horror Story':
        system_prompt = 'You are a world class horror author with a style similar to Stephen King and Anne Rice. Generate content that contains logical twists and builds suspense. Produce content step by step.'
    else:
        system_prompt = 'You are a world class romance novelist with a style similar to Nora Roberts and Jane Austen. Generate content that is tantilizing, lustrious, and very erotic. Produce content step by step.'

   #create output style logic 
    if os == 'Outline':
        style = 'Respond with an outline no longer than 500 words'
    elif os == 'Paragraph':
        style = 'Respond with at least one paragraph. Output at least 200 words.'
    else:
        style = 'Respond with a top 15 list. Output is limited to 150 words.'
    
    #build messages payload
    messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": style},
            {"role": "assistant", "content": "On what topic?"},
            {"role": "user", "content": input_value}
        ]

    
    #button logic to submit to ChatGPT API
    if 'gen-button' in changed_id:
        print(input_value)
        if input_value is None or input_value == "":
            input_value = ""
            text = html.P('hello <br> this is </br> a <br> test ')

        else:
            print(input_value)
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=messages,
                temperature = 0.8,
                top_p = 1, 
                presence_penalty = 0.5,
                frequency_penalty = 0.4            
            )
            text = (response['choices'][0]['message']['content'])

    return html.P(text, style = {'white-space': 'pre-wrap'})

Поскольку input_value равно None при запуске приложения, мы используем оператор If/Else для обработки None и предотвращения отображения ошибки при загрузке приложения. Когда мы вводим текстовое приглашение и нажимаем кнопку «Создать текст», значение input_value добавляется к полезной нагрузке messages и передается в модель. Обратный вызов возвращает сгенерированный текст, заключенный в компонент html.P.

Поздравляем! Мы только что создали функциональное приложение-помощник по письму, используя API ChatGPT!

Дальнейшие шаги и полный код

Dash by Plotly — это простой, но мощный способ запуска и запуска веб-приложений с помощью небольшого количества кода. В этом уроке мы только коснулись того, что возможно с Dash. Мы могли бы расширить это приложение, добавив аутентификацию пользователей, разместив его на веб-сервере и добавив дополнительные элементы управления, влияющие на логику запросов. Я также настоятельно рекомендую поиграться с параметрами API ChatGPT. Вы можете поиграть с ними бесплатно на Игровой площадке OpenAI и поэкспериментировать, прежде чем настраивать логику в приложении.

Спасибо, что прочитали мой учебник по chatGPT и Dash!

Посмотрите полный код в моем репозитории на GitHub!

Спасибо!

— Эрик Клеппен