Поделиться через


Начало работы с помощниками Azure OpenAI (предварительная версия)

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

Примечание.

  • Поиск по файлам может получать до 10 000 файлов на помощник – 500 раз больше, чем раньше. Это быстро, поддерживает параллельные запросы с помощью многопоточных поисковых запросов, а также функции расширенного перерасписывания и перезаписи запросов.
    • Векторное хранилище — это новый объект в API. После добавления файла в векторное хранилище он автоматически анализируется, блокируется и внедряется, подготавливается к поиску. Хранилища векторов можно использовать в помощник и потоках, упрощая управление файлами и выставление счетов.
  • Мы добавили поддержку tool_choice параметра, который можно использовать для принудительного использования определенного средства (например, поиска файлов, интерпретатора кода или функции) в определенном запуске.

Поддержка помощников

Поддержка регионов и моделей

Интерпретатор кода доступен во всех регионах, поддерживаемых помощниками Azure OpenAI. Страница моделей содержит самые актуальные сведения о регионах и моделях, где в настоящее время поддерживаются помощники.

Версии API

  • 2024-02-15-preview
  • 2024-05-01-preview

Поддерживаемые типы файлов

File format Тип MIME Интерпретатор кода
c. text/x-c
.cpp text/x-c++
.csv application/csv
DOCX application/vnd.openxmlformats-officedocument.wordprocessingml.document
.html text/html
.java text/x-java
json. application/json
.md text/markdown
PDF application/pdf
.php text/x-php
PPTX application/vnd.openxmlformats-officedocument.presentationml.presentationml.presentation
.py text/x-python
.py text/x-script.python
.Rb text/x-ruby
.Tex text/x-tex
.txt text/plain
.css text/css
.jpeg image/jpeg
JPG image/jpeg
.js text/javascript
.gif image/gif
PNG image/png
.Смолы application/x-tar
.ts application/typescript
XLSX application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
XML application/xml или text/xml
.zip application/zip

Инструменты

Совет

Мы добавили поддержку tool_choice параметра, который можно использовать для принудительного использования определенного средства (например file_search, code_interpreterили а function) в определенном запуске.

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

Файлы

Файлы можно отправлять через Студию или программным способом. Этот file_ids параметр необходим для предоставления таких средств, как code_interpreter доступ к файлам. При использовании конечной точки отправки файла необходимо задать purpose для помощник, которые будут использоваться с API помощников.

Детская площадка помощников

Мы предоставляем пошаговое руководство по игровой площадке Помощников. Это обеспечивает среду без кода для тестирования возможностей помощник.

Компоненты помощников

Компонент Description
Помощник Настраиваемый ИИ, использующий модели Azure OpenAI в сочетании с инструментами.
Поток Сеанс беседы между помощником и пользователем. Потоки хранят сообщения и автоматически обрабатывают усечение, чтобы поместить содержимое в контекст модели.
Сообщение Сообщение, созданное помощником или пользователем. Сообщения могут включать текст, изображения и другие файлы. Сообщения хранятся в виде списка в потоке.
Выполнить Активация помощника для запуска на основе содержимого потока. Помощник использует свою конфигурацию и сообщения потока для выполнения задач путем вызова моделей и инструментов. В рамках выполнения помощник добавляет сообщения в поток.
Шаг выполнения Подробный список шагов, выполняемых помощником в рамках запуска. Помощник может вызывать средства или создавать сообщения во время его выполнения. Изучение шагов выполнения позволяет понять, как помощник получает свои окончательные результаты.

Настройка первого помощника

Создание помощник

В этом примере мы создадим помощник, которая записывает код для создания визуализаций с помощью возможностей code_interpreter средства. Приведенные ниже примеры предназначены для последовательного выполнения в среде, например Jupyter Notebook.

import os
import json
from openai import AzureOpenAI
    
client = AzureOpenAI(
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
    api_version="2024-05-01-preview",
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    )

# Create an assistant
assistant = client.beta.assistants.create(
    name="Data Visualization",
    instructions=f"You are a helpful AI assistant who makes interesting visualizations based on data." 
    f"You have access to a sandboxed environment for writing and testing code."
    f"When you are asked to create a visualization you should follow these steps:"
    f"1. Write the code."
    f"2. Anytime you write new code display a preview of the code to show your work."
    f"3. Run the code to confirm that it runs."
    f"4. If the code is successful display the visualization."
    f"5. If the code is unsuccessful display the error message and try to revise the code and rerun going through the steps from above again.",
    tools=[{"type": "code_interpreter"}],
    model="gpt-4-1106-preview" #You must replace this value with the deployment name for your model.
)

Ниже приведены некоторые сведения о конфигурации, приведенной выше.

  • Мы разрешаем этому помощник доступ к интерпретатору кода с помощью строкиtools=[{"type": "code_interpreter"}],. Это дает модели доступ к песочнице python для запуска и выполнения кода, чтобы помочь сформулировать ответы на вопрос пользователя.
  • В инструкциях мы напоминаем модели о том, что она может выполнять код. Иногда модель нуждается в том, чтобы направлять ее к правильному инструменту для решения заданного запроса. Если вы знаете, что вы хотите использовать определенную библиотеку для создания определенного ответа, который вы знаете, является частью интерпретатора кода, он может помочь предоставить рекомендации, сказав следующее: "Использовать Matplotlib для выполнения x".
  • Так как это Azure OpenAI, значение, которое необходимо ввести, model=должно соответствовать имени развертывания.

Далее мы напечатаем содержимое помощник, которое мы только что создали для подтверждения успешного создания:

print(assistant.model_dump_json(indent=2))
{
  "id": "asst_7AZSrv5I3XzjUqWS40X5UgRr",
  "created_at": 1705972454,
  "description": null,
  "file_ids": [],
  "instructions": "You are a helpful AI assistant who makes interesting visualizations based on data.You have access to a sandboxed environment for writing and testing code.When you are asked to create a visualization you should follow these steps:1. Write the code.2. Anytime you write new code display a preview of the code to show your work.3. Run the code to confirm that it runs.4. If the code is successful display the visualization.5. If the code is unsuccessful display the error message and try to revise the code and rerun going through the steps from above again.",
  "metadata": {},
  "model": "gpt-4-1106-preview",
  "name": "Data Visualization",
  "object": "assistant",
  "tools": [
    {
      "type": "code_interpreter"
    }
  ]
}

Создание потока

Теперь создадим поток.

# Create a thread
thread = client.beta.threads.create()
print(thread)
Thread(id='thread_6bunpoBRZwNhovwzYo7fhNVd', created_at=1705972465, metadata={}, object='thread')

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

Затем создайте первый вопрос пользователя для добавления в поток.

# Add a user question to the thread
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Create a visualization of a sinewave"
)

Вывод списка сообщений потоков

thread_messages = client.beta.threads.messages.list(thread.id)
print(thread_messages.model_dump_json(indent=2))
{
  "data": [
    {
      "id": "msg_JnkmWPo805Ft8NQ0gZF6vA2W",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Create a visualization of a sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705972476,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_6bunpoBRZwNhovwzYo7fhNVd"
    }
  ],
  "object": "list",
  "first_id": "msg_JnkmWPo805Ft8NQ0gZF6vA2W",
  "last_id": "msg_JnkmWPo805Ft8NQ0gZF6vA2W",
  "has_more": false
}

Выполнение потока

run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id,
  #instructions="New instructions" #You can optionally provide new instructions but these will override the default instructions
)

Мы также могли бы передать instructions здесь параметр, но это переопределит существующие инструкции, которые мы уже предоставили для помощник.

Получение состояния потока

# Retrieve the status of the run
run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)

status = run.status
print(status)
completed

В зависимости от сложности выполняемого запроса поток может занять больше времени. В этом случае можно создать цикл для мониторинга состояния выполнения потока с кодом, как показано ниже:

import time
from IPython.display import clear_output

start_time = time.time()

status = run.status

while status not in ["completed", "cancelled", "expired", "failed"]:
    time.sleep(5)
    run = client.beta.threads.runs.retrieve(thread_id=thread.id,run_id=run.id)
    print("Elapsed time: {} minutes {} seconds".format(int((time.time() - start_time) // 60), int((time.time() - start_time) % 60)))
    status = run.status
    print(f'Status: {status}')
    clear_output(wait=True)

messages = client.beta.threads.messages.list(
  thread_id=thread.id
) 

print(f'Status: {status}')
print("Elapsed time: {} minutes {} seconds".format(int((time.time() - start_time) // 60), int((time.time() - start_time) % 60)))
print(messages.model_dump_json(indent=2))

При выполнении in_progress или в других нетерминальных состояниях поток заблокирован. Если поток заблокирован, новые сообщения не могут быть добавлены, а новые запуски не могут быть созданы.

Вывод списка сообщений потоков после выполнения

Когда состояние выполнения указывает на успешное завершение, вы можете снова перечислить содержимое потока, чтобы получить ответ модели и любые средства:

messages = client.beta.threads.messages.list(
  thread_id=thread.id
)

print(messages.model_dump_json(indent=2))
{
  "data": [
    {
      "id": "msg_M5pz73YFsJPNBbWvtVs5ZY3U",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Is there anything else you would like to visualize or any additional features you'd like to add to the sine wave plot?"
          },
          "type": "text"
        }
      ],
      "created_at": 1705967782,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_AGQHJrrfV3eM0eI9T3arKgYY",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_oJbUanImBRpRran5HSa4Duy4",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "image_file": {
            "file_id": "assistant-1YGVTvNzc2JXajI5JU9F0HMD"
          },
          "type": "image_file"
        },
        {
          "text": {
            "annotations": [],
            "value": "Here is the visualization of a sine wave: \n\nThe wave is plotted using values from 0 to \\( 4\\pi \\) on the x-axis, and the corresponding sine values on the y-axis. I've also added grid lines for easier reading of the plot."
          },
          "type": "text"
        }
      ],
      "created_at": 1705967044,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_8PsweDFn6gftUd91H87K0Yts",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Create a visualization of a sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705966634,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    }
  ],
  "object": "list",
  "first_id": "msg_M5pz73YFsJPNBbWvtVs5ZY3U",
  "last_id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
  "has_more": false
}

Получение идентификатора файла

Мы попросили, чтобы модель создавала изображение синусовой волны. Чтобы скачать изображение, сначала необходимо получить идентификатор файла изображений.

data = json.loads(messages.model_dump_json(indent=2))  # Load JSON data into a Python object
image_file_id = data['data'][0]['content'][0]['image_file']['file_id']

print(image_file_id)  # Outputs: assistant-1YGVTvNzc2JXajI5JU9F0HMD

Скачивание образа

content = client.files.content(image_file_id)

image= content.write_to_file("sinewave.png")

Откройте образ локально после скачивания:

from PIL import Image

# Display the image in the default image viewer
image = Image.open("sinewave.png")
image.show()

Снимок экрана: интерпретатор кода, созданный волной синуса.

Задайте следующий вопрос в потоке

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

# Add a new user question to the thread
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="Show me the code you used to generate the sinewave"
)

Снова необходимо выполнить и получить состояние потока:

run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id,
  #instructions="New instructions" #You can optionally provide new instructions  but these will override the default instructions
)

# Retrieve the status of the run
run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)

status = run.status
print(status)

completed

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

messages = client.beta.threads.messages.list(
  thread_id=thread.id
)

print(messages.model_dump_json(indent=2))
{
  "data": [
    {
      "id": "msg_oaF1PUeozAvj3KrNnbKSy4LQ",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Certainly, here is the code I used to generate the sine wave visualization:\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Generating data for the sinewave\nx = np.linspace(0, 4 * np.pi, 1000)  # Generate values from 0 to 4*pi\ny = np.sin(x)  # Compute the sine of these values\n\n# Plotting the sine wave\nplt.plot(x, y)\nplt.title('Sine Wave')\nplt.xlabel('x')\nplt.ylabel('sin(x)')\nplt.grid(True)\nplt.show()\n```\n\nThis code snippet uses `numpy` to generate an array of x values and then computes the sine for each x value. It then uses `matplotlib` to plot these values and display the resulting graph."
          },
          "type": "text"
        }
      ],
      "created_at": 1705969710,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_oDS3fH7NorCUVwROTZejKcZN",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_moYE3aNwFYuRq2aXpxpt2Wb0",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Show me the code you used to generate the sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705969678,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_M5pz73YFsJPNBbWvtVs5ZY3U",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Is there anything else you would like to visualize or any additional features you'd like to add to the sine wave plot?"
          },
          "type": "text"
        }
      ],
      "created_at": 1705967782,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_AGQHJrrfV3eM0eI9T3arKgYY",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_oJbUanImBRpRran5HSa4Duy4",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "image_file": {
            "file_id": "assistant-1YGVTvNzc2JXajI5JU9F0HMD"
          },
          "type": "image_file"
        },
        {
          "text": {
            "annotations": [],
            "value": "Here is the visualization of a sine wave: \n\nThe wave is plotted using values from 0 to \\( 4\\pi \\) on the x-axis, and the corresponding sine values on the y-axis. I've also added grid lines for easier reading of the plot."
          },
          "type": "text"
        }
      ],
      "created_at": 1705967044,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_8PsweDFn6gftUd91H87K0Yts",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Create a visualization of a sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705966634,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    }
  ],
  "object": "list",
  "first_id": "msg_oaF1PUeozAvj3KrNnbKSy4LQ",
  "last_id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
  "has_more": false
}

Чтобы извлечь только ответ на наш последний вопрос:

data = json.loads(messages.model_dump_json(indent=2))
code = data['data'][0]['content'][0]['text']['value']
print(code)

Конечно, вот код, который я использовал для создания визуализации синусовой волны:

import numpy as np
import matplotlib.pyplot as plt

# Generating data for the sinewave
x = np.linspace(0, 4 * np.pi, 1000)  # Generate values from 0 to 4*pi
y = np.sin(x)  # Compute the sine of these values

# Plotting the sine wave
plt.plot(x, y)
plt.title('Sine Wave')
plt.xlabel('x')
plt.ylabel('sin(x)')
plt.grid(True)
plt.show()

Темный режим

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

# Add a user question to the thread
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="I prefer visualizations in darkmode can you change the colors to make a darkmode version of this visualization."
)

# Run the thread
run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id,
)

# Retrieve the status of the run
run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)

status = run.status
print(status)
completed
messages = client.beta.threads.messages.list(
  thread_id=thread.id
)

print(messages.model_dump_json(indent=2))
{
  "data": [
    {
      "id": "msg_KKzOHCArWGvGpuPo0pVZTHgV",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "You're viewing the dark mode version of the sine wave visualization in the image above. The plot is set against a dark background with a cyan colored sine wave for better contrast and visibility. If there's anything else you'd like to adjust or any other assistance you need, feel free to let me know!"
          },
          "type": "text"
        }
      ],
      "created_at": 1705971199,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_izZFyTVB1AlFM1VVMItggRn4",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_30pXFVYNgP38qNEMS4Zbozfk",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "I prefer visualizations in darkmode can you change the colors to make a darkmode version of this visualization."
          },
          "type": "text"
        }
      ],
      "created_at": 1705971194,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_3j31M0PaJLqO612HLKVsRhlw",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "image_file": {
            "file_id": "assistant-kfqzMAKN1KivQXaEJuU0u9YS"
          },
          "type": "image_file"
        },
        {
          "text": {
            "annotations": [],
            "value": "Here is the dark mode version of the sine wave visualization. I've used the 'dark_background' style in Matplotlib and chosen a cyan color for the plot line to ensure it stands out against the dark background."
          },
          "type": "text"
        }
      ],
      "created_at": 1705971123,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_B91erEPWro4bZIfryQeIDDlx",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_FgDZhBvvM1CLTTFXwgeJLdua",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "I prefer visualizations in darkmode can you change the colors to make a darkmode version of this visualization."
          },
          "type": "text"
        }
      ],
      "created_at": 1705971052,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_oaF1PUeozAvj3KrNnbKSy4LQ",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Certainly, here is the code I used to generate the sine wave visualization:\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Generating data for the sinewave\nx = np.linspace(0, 4 * np.pi, 1000)  # Generate values from 0 to 4*pi\ny = np.sin(x)  # Compute the sine of these values\n\n# Plotting the sine wave\nplt.plot(x, y)\nplt.title('Sine Wave')\nplt.xlabel('x')\nplt.ylabel('sin(x)')\nplt.grid(True)\nplt.show()\n```\n\nThis code snippet uses `numpy` to generate an array of x values and then computes the sine for each x value. It then uses `matplotlib` to plot these values and display the resulting graph."
          },
          "type": "text"
        }
      ],
      "created_at": 1705969710,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_oDS3fH7NorCUVwROTZejKcZN",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_moYE3aNwFYuRq2aXpxpt2Wb0",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Show me the code you used to generate the sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705969678,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_M5pz73YFsJPNBbWvtVs5ZY3U",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Is there anything else you would like to visualize or any additional features you'd like to add to the sine wave plot?"
          },
          "type": "text"
        }
      ],
      "created_at": 1705967782,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_AGQHJrrfV3eM0eI9T3arKgYY",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_oJbUanImBRpRran5HSa4Duy4",
      "assistant_id": "asst_eHwhP4Xnad0bZdJrjHO2hfB4",
      "content": [
        {
          "image_file": {
            "file_id": "assistant-1YGVTvNzc2JXajI5JU9F0HMD"
          },
          "type": "image_file"
        },
        {
          "text": {
            "annotations": [],
            "value": "Here is the visualization of a sine wave: \n\nThe wave is plotted using values from 0 to \\( 4\\pi \\) on the x-axis, and the corresponding sine values on the y-axis. I've also added grid lines for easier reading of the plot."
          },
          "type": "text"
        }
      ],
      "created_at": 1705967044,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_8PsweDFn6gftUd91H87K0Yts",
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    },
    {
      "id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
      "assistant_id": null,
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "Create a visualization of a sinewave"
          },
          "type": "text"
        }
      ],
      "created_at": 1705966634,
      "file_ids": [],
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_ow1Yv29ptyVtv7ixbiKZRrHd"
    }
  ],
  "object": "list",
  "first_id": "msg_KKzOHCArWGvGpuPo0pVZTHgV",
  "last_id": "msg_Pu3eHjM10XIBkwqh7IhnKKdG",
  "has_more": false
}

Извлеките новый идентификатор файла образа и скачайте и отобразите изображение:

data = json.loads(messages.model_dump_json(indent=2))  # Load JSON data into a Python object
image_file_id = data['data'][0]['content'][0]['image_file']['file_id'] # index numbers can vary if you have had a different conversation over the course of the thread.

print(image_file_id)

content = client.files.content(image_file_id)
image= content.write_to_file("dark_sine.png")

# Display the image in the default image viewer
image = Image.open("dark_sine.png")
image.show()

Снимок экрана: интерпретатор кода, созданный синусной волной в темном режиме.

Дополнительная справка

Выполнение определений состояния

Состояние Определение
queued При первом создании запусков или при завершении required_action они перемещаются в состояние очереди. Они должны почти сразу перейти к in_progress.
in_progress Во время in_progress помощник использует модель и средства для выполнения действий. Ход выполнения можно просмотреть, проверив шаги выполнения.
completed Выполнение успешно завершено! Теперь вы можете просмотреть все сообщения, добавленные помощником в поток, и все действия, которые выполнили выполнение. Вы также можете продолжить беседу, добавив в поток больше пользовательских сообщений и создав другой запуск.
requires_action При использовании средства вызова функции выполнение перейдет в состояние required_action после определения имен и аргументов вызываемых функций. Затем необходимо запустить эти функции и отправить выходные данные перед выполнением. Если выходные данные не предоставляются до прохождения метки времени expires_at (примерно 10 минут после создания), выполнение переместится в состояние с истекшим сроком действия.
expired Это происходит, когда выходные данные вызова функции не были отправлены до expires_at и истекает срок действия выполнения. Кроме того, если выполнение выполняется слишком долго и выходит за рамки времени, указанного в expires_at, срок действия наших систем истекает.
cancelling Вы можете попытаться отменить in_progress запустить с помощью конечной точки "Отмена запуска". После успешной попытки отмены состояние выполнения переходит к отмене. Отмена выполняется, но не гарантируется.
cancelled Выполнение было успешно отменено.
failed Чтобы просмотреть причину сбоя last_error , просмотрите объект в run. Метка времени сбоя будет записана в failed_at.

Заметки к сообщениям

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

Когда заметки присутствуют в массиве содержимого сообщения, вы увидите неразборчивые подстроки, созданные моделью, в тексте, который необходимо заменить правильными заметками. Эти строки могут выглядеть примерно так 【13†source】 или sandbox:/mnt/data/file.csv. Ниже приведен фрагмент кода Python из OpenAI, который заменяет эти строки сведениями, представленными в заметках.


from openai import AzureOpenAI
    
client = AzureOpenAI(
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
    api_version="2024-05-01-preview",
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    )

# Retrieve the message object
message = client.beta.threads.messages.retrieve(
  thread_id="...",
  message_id="..."
)

# Extract the message content
message_content = message.content[0].text
annotations = message_content.annotations
citations = []

# Iterate over the annotations and add footnotes
for index, annotation in enumerate(annotations):
    # Replace the text with a footnote
    message_content.value = message_content.value.replace(annotation.text, f' [{index}]')

    # Gather citations based on annotation attributes
    if (file_citation := getattr(annotation, 'file_citation', None)):
        cited_file = client.files.retrieve(file_citation.file_id)
        citations.append(f'[{index}] {file_citation.quote} from {cited_file.filename}')
    elif (file_path := getattr(annotation, 'file_path', None)):
        cited_file = client.files.retrieve(file_path.file_id)
        citations.append(f'[{index}] Click <here> to download {cited_file.filename}')
        # Note: File download functionality not implemented above for brevity

# Add footnotes to the end of the message before displaying to user
message_content.value += '\n' + '\n'.join(citations)

Заметка к сообщению Description
file_citation Ссылки на файлы создаются средством извлечения и определяют ссылки на определенную цитату в определенном файле, который был отправлен и используется помощником для создания ответа.
file_path Заметки пути к файлу создаются средством code_interpreter и содержат ссылки на файлы, созданные средством.

См. также