openai-api-rs для Rust: полное руководство с примерами
Библиотека openai-api-rs — это современный, асинхронный и типобезопасный клиент для OpenAI API, написанный на языке Rust. Она предоставляет разработчикам удобный интерфейс для взаимодействия с моделями GPT (включая GPT-4, GPT-3.5), DALL-E (генерация изображений), Whisper (распознавание речи), а также для работы с эмбеддингами, модерацией контента и управлением файлами. Библиотека полностью поддерживает потоковую передачу (streaming) ответов, что критически важно для создания интерактивных чат-приложений и ассистентов с низкой задержкой.
Зачем использовать Rust для работы с OpenAI API? Rust обеспечивает высочайшую производительность и безопасность памяти без сборщика мусора. Это делает openai-api-rs идеальным выбором для высоконагруженных серверных приложений, ботов для Telegram/Discord, систем обработки естественного языка в реальном времени и встраиваемых устройств. Благодаря строгой системе типов Rust, многие ошибки (например, неправильный формат запроса) отлавливаются на этапе компиляции, а не в рантайме. Библиотека построена на базе reqwest и tokio, что гарантирует эффективную работу с асинхронными операциями ввода-вывода.
На образовательном сайте PythonLib мы рассматриваем эту библиотеку, чтобы показать, как экосистема Rust может быть использована для задач машинного обучения и NLP. Даже если вы пишете на Python, понимание Rust-клиентов поможет вам лучше осознать внутреннее устройство API-запросов и принципы обработки потоковых данных. Библиотека активно поддерживается сообществом, имеет подробную документацию и покрыта тестами.
Установка
Для установки библиотеки openai-api-rs в ваш проект на Rust, выполните команду в терминале в корневой директории проекта:
cargo add openai-api-rs
Эта команда добавит последнюю версию библиотеки в файл Cargo.toml. Если вы предпочитаете ручное редактирование, добавьте следующую строку в раздел [dependencies]:
[dependencies]
openai-api-rs = "0.2" # Проверьте актуальную версию на crates.io
Также вам понадобится асинхронный рантайм. Рекомендуется использовать tokio:
cargo add tokio --features full
Не забудьте установить переменную окружения OPENAI_API_KEY с вашим ключом API от OpenAI. Это можно сделать в терминале:
export OPENAI_API_KEY="sk-ваш_ключ_здесь"
Или передавать ключ напрямую в код (не рекомендуется для продакшена).
Быстрый старт
Минимальный рабочий пример: отправка простого запроса к модели GPT-3.5 и вывод ответа в консоль.
use openai_api_rs::v1::api::Client;
use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Создаем клиент, используя API ключ из переменной окружения
let client = Client::new(env::var("OPENAI_API_KEY")?);
// Формируем запрос
let request = ChatCompletionRequest::new(
"gpt-3.5-turbo".to_string(),
vec![Message {
role: "user".to_string(),
content: "Напиши короткое стихотворение о Rust".to_string(),
}],
);
// Отправляем запрос и получаем ответ
let response = client.chat_completion(request).await?;
// Извлекаем текст ответа
if let Some(choice) = response.choices.first() {
println!("Ответ: {}", choice.message.content);
}
Ok(())
}
Запустите программу командой cargo run. Вы должны увидеть сгенерированное стихотворение. Этот пример демонстрирует базовую механику: создание клиента, формирование запроса и обработка ответа.
Основные методы и структуры
Ниже представлены ключевые методы библиотеки openai-api-rs. Каждый метод сопровождается сигнатурой, описанием и рабочим примером кода.
1. Client::new(api_key: String) -> Client
Что делает: Создает новый экземпляр клиента для взаимодействия с OpenAI API. Принимает API-ключ в качестве строки. Клиент будет использоваться для всех последующих запросов.
use openai_api_rs::v1::api::Client;
let client = Client::new("sk-...".to_string());
// или через переменную окружения:
let client = Client::new(std::env::var("OPENAI_API_KEY").unwrap());
2. client.chat_completion(request: ChatCompletionRequest) -> Result<ChatCompletionResponse>
Что делает: Отправляет запрос к чат-модели (GPT-3.5, GPT-4). Принимает структуру ChatCompletionRequest, содержащую модель, список сообщений и опциональные параметры (температура, max_tokens и т.д.). Возвращает ответ с выборками (choices).
use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};
let request = ChatCompletionRequest::new(
"gpt-4".to_string(),
vec![
Message { role: "system".to_string(), content: "Ты — полезный ассистент.".to_string() },
Message { role: "user".to_string(), content: "Расскажи про Rust".to_string() },
],
);
let response = client.chat_completion(request).await?;
println!("{}", response.choices[0].message.content);
3. client.chat_completion_stream(request: ChatCompletionRequest) -> impl Stream<Item = Result<ChatCompletionChunk>>
Что делает: Отправляет запрос к чат-модели в потоковом режиме (streaming). Ответ приходит частями (chunks) по мере генерации текста. Возвращает асинхронный поток (Stream), который можно обрабатывать по мере поступления данных. Идеально для создания эффекта печатающегося текста.
use futures_util::StreamExt;
use openai_api_rs::v1::chat_completion::ChatCompletionRequest;
let request = ChatCompletionRequest::new(
"gpt-3.5-turbo".to_string(),
vec![Message { role: "user".to_string(), content: "Напиши историю из 3 предложений".to_string() }],
);
let mut stream = client.chat_completion_stream(request).await?;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
if let Some(delta) = chunk.choices.first().and_then(|c| c.delta.content.as_ref()) {
print!("{}", delta);
}
}
4. client.create_image(request: ImageGenerationRequest) -> Result<ImageResponse>
Что делает: Генерирует изображение на основе текстового описания (prompt) с использованием модели DALL-E. Принимает структуру ImageGenerationRequest, где можно указать размер, количество изображений и стиль. Возвращает URL или base64-кодированное изображение.
use openai_api_rs::v1::image::{ImageGenerationRequest, ImageSize};
let request = ImageGenerationRequest::new(
"Кот в космосе, цифровая живопись".to_string(),
ImageSize::S1024x1024,
1,
);
let response = client.create_image(request).await?;
if let Some(url) = response.data.first().and_then(|d| d.url.as_ref()) {
println!("URL изображения: {}", url);
}
5. client.create_embedding(request: EmbeddingRequest) -> Result<EmbeddingResponse>
Что делает: Создает векторное представление (эмбеддинг) для входного текста. Эмбеддинги используются для поиска по смыслу, кластеризации и классификации текстов. Модель по умолчанию — text-embedding-ada-002.
use openai_api_rs::v1::embedding::EmbeddingRequest;
let request = EmbeddingRequest::new(
"text-embedding-ada-002".to_string(),
"Rust — это язык системного программирования".to_string(),
);
let response = client.create_embedding(request).await?;
let embedding = &response.data[0].embedding;
println!("Размерность эмбеддинга: {}", embedding.len()); // 1536 для ada-002
6. client.create_transcription(request: AudioTranscriptionRequest) -> Result<TranscriptionResponse>
Что делает: Транскрибирует аудиофайл в текст с помощью модели Whisper. Поддерживает форматы: flac, m4a, mp3, mp4, mpeg, mpga, oga, ogg, wav, webm. Принимает путь к файлу и опционально язык.
use openai_api_rs::v1::audio::{AudioTranscriptionRequest, AudioInput};
let request = AudioTranscriptionRequest::new(
AudioInput::File("speech.mp3".to_string()),
"whisper-1".to_string(),
);
let response = client.create_transcription(request).await?;
println!("Транскрипция: {}", response.text);
7. client.create_moderation(request: ModerationRequest) -> Result<ModerationResponse>
Что делает: Проверяет текст на наличие нежелательного контента (ненависть, насилие, сексуальный контент и т.д.). Возвращает флаги по каждой категории и общий флаг flagged. Полезно для фильтрации пользовательского ввода.
use openai_api_rs::v1::moderation::ModerationRequest;
let request = ModerationRequest::new("Я тебя ненавижу!".to_string());
let response = client.create_moderation(request).await?;
println!("Флаг: {}", response.results[0].flagged); // true, если контент нарушает правила
8. client.list_models() -> Result<ListModelsResponse>
Что делает: Получает список всех доступных моделей OpenAI. Возвращает информацию о каждой модели: ID, владелец, дата создания и т.д. Полезно для динамического выбора модели в приложении.
let response = client.list_models().await?;
for model in response.data {
println!("ID: {}, Владелец: {}", model.id, model.owned_by);
}
9. client.retrieve_model(model_id: &str) -> Result<Model>
Что делает: Получает детальную информацию о конкретной модели по её ID. Возвращает структуру Model с полями: id, object, created, owned_by, permission, root, parent.
let model = client.retrieve_model("gpt-4").await?;
println!("Модель: {}, создана: {}", model.id, model.created);
10. client.delete_model(model_id: &str) -> Result<DeleteModelResponse>
Что делает: Удаляет тонко настроенную (fine-tuned) модель. Работает только с моделями, созданными пользователем. Возвращает статус удаления. Внимание: это действие необратимо.
let response = client.delete_model("ft:gpt-3.5-turbo:my-org::custom_id").await?;
println!("Удалено: {}", response.deleted);
Реальный практический пример: Чат-бот с историей и потоковым выводом
В этом примере мы создадим консольный чат-бот, который сохраняет историю диалога и выводит ответы в реальном времени (streaming). Пользователь может вводить сообщения, а бот отвечает, учитывая контекст предыдущих сообщений. Для выхода из чата введите "exit".
use openai_api_rs::v1::api::Client;
use openai_api_rs::v1::chat_completion::{ChatCompletionRequest, Message};
use futures_util::StreamExt;
use std::env;
use std::io::{self, Write};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Инициализация клиента
let api_key = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY не установлен");
let client = Client::new(api_key);
// История диалога: начинаем с системного сообщения
let mut messages: Vec<Message> = vec![
Message {
role: "system".to_string(),
content: "Ты — дружелюбный ассистент. Отвечай кратко и по делу.".to_string(),
},
];
println!("Чат-бот запущен. Введите 'exit' для выхода.\n");
loop {
// Ввод пользователя
print!("Вы: ");
io::stdout().flush()?;
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
let user_input = user_input.trim().to_string();
if user_input.eq_ignore_ascii_case("exit") {
println!("До свидания!");
break;
}
// Добавляем сообщение пользователя в историю
messages.push(Message {
role: "user".to_string(),
content: user_input,
});
// Формируем запрос с потоковым выводом
let request = ChatCompletionRequest::new(
"gpt-3.5-turbo".to_string(),
messages.clone(), // передаем всю историю
);
print!("Бот: ");
io::stdout().flush()?;
let mut full_response = String::new();
let mut stream = client.chat_completion_stream(request).await?;
// Обрабатываем потоковые чанки
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
if let Some(delta) = chunk.choices.first()
.and_then(|c Также в библиотеке
ESLint + TypeScript плагины для TypeScript: полное руководство с примерами
SFML для C++: полное руководство с примерами
Работа с изображениями в PHP: полное руководство по GD и Imagick
Работа с S3 и облачными хранилищами в C# (.NET): библиотека AWS SDK