В этой статье
Перевод из терминала начинается не с curl. Сначала сохраните исходный текст в UTF-8, затем явно опишите задачу для модели и только после этого проверьте, что ответ не потерял важную деталь.
Ниже — один маршрут для Linux, macOS и Windows PowerShell. Он не использует Python SDK и веб-интерфейс ChatGPT: текст уходит из локального файла в Responses API.
Подготовьте исходный файл
Создайте файл source.txt и сохраните его в UTF-8 без изменения строк. Например:
Пожалуйста, пришлите финальную версию договора до пятницы. Если срок изменится, сообщите заранее.
В этом примере язык оригинала — русский, язык перевода — английский. Важны не только слова, но и три условия: срок «до пятницы», оговорка об изменении срока и вежливый тон.
API-ключ не записывайте в source.txt, скрипт или репозиторий. Передайте его процессу через переменную окружения. Модель тоже задайте переменной: конкретное имя должно быть доступно вашему API-проекту. В примерах ниже указано gpt-5.2 как заменяемое значение, а не как гарантия доступа.
Для запроса Responses API используется POST /v1/responses; в теле нужны как минимум model и input. Документация метода создания ответа описывает эти поля и структуру результата.
Linux и macOS: отправьте файл через curl
Сначала задайте ключ только в текущей сессии терминала:
export OPENAI_API_KEY='ваш_ключ_из_переменных_окружения'
В реальной работе удобнее получить его из защищённого хранилища или заранее настроенной переменной окружения. Не вставляйте настоящий ключ в команду, которую собираетесь сохранять или отправлять кому-то.
Соберите JSON из файла с помощью jq. Ключ --rawfile читает содержимое source.txt как строку и корректно экранирует кавычки и переводы строк внутри JSON:
jq -n \
--arg model 'gpt-5.2' \
--rawfile source 'source.txt' \
'{
model: $model,
input: (
"Переведи следующий текст с русского на английский.\n" +
"Сохрани смысл, числа, даты, имена и условия.\n" +
"Контекст: деловая переписка о договоре.\n" +
"Не добавляй комментарии, пояснения или вступление — верни только перевод.\n\n" +
$source
)
}' > request.json
Теперь отправьте запрос. Тело ответа останется чистым JSON в response.json, а HTTP-код попадёт в отдельную переменную:
status=$(curl --silent --show-error \
--output response.json \
--write-out '%{http_code}' \
--request POST 'https://api.openai.com/v1/responses' \
--header "Authorization: Bearer $OPENAI_API_KEY" \
--header 'Content-Type: application/json' \
--data-binary @request.json)
printf 'HTTP status: %s\n' "$status"
Здесь Authorization: Bearer ... и Content-Type: application/json передаются в заголовках, как в официальном примере для curl. Руководство по моделям и запросам поможет сверить актуальное имя доступной модели.
Код 2xx показывает, что запрос принят, но не доказывает качество перевода. Поэтому сохраняйте response.json и разбирайте его после запроса. При ошибке проверьте код, модель, права проекта и лимиты, не публикуя сам ключ.
Ожидаемый синтетический перевод для исходной фразы может выглядеть так:
Please send the final version of the contract by Friday. If the deadline changes, please let me know in advance.
Этот фрагмент — иллюстрация ожидаемого содержания, а не результат выполненного здесь API-запроса.
Windows PowerShell: тот же запрос без Python
В PowerShell ключ можно временно задать так:
$env:OPENAI_API_KEY = 'ваш_ключ_из_переменных_окружения'
Прочитайте файл целиком и соберите объект запроса. -Raw не даёт PowerShell превратить каждую строку исходника в отдельное поле.
$source = Get-Content -Raw -Encoding utf8 .\source.txt
$body = @{
model = 'gpt-5.2'
input = @"
Переведи следующий текст с русского на английский.
Сохрани смысл, числа, даты, имена и условия.
Контекст: деловая переписка о договоре.
Не добавляй комментарии, пояснения или вступление — верни только перевод.
$source
"@
} | ConvertTo-Json -Depth 10
$response = Invoke-WebRequest `
-Method Post `
-Uri 'https://api.openai.com/v1/responses' `
-Headers @{ Authorization = "Bearer $env:OPENAI_API_KEY" } `
-ContentType 'application/json; charset=utf-8' `
-Body ([Text.Encoding]::UTF8.GetBytes($body))
Write-Output "HTTP status: $($response.StatusCode)"
$response.Content | Set-Content -Encoding utf8 .\response.json
Перед запуском проверьте, что source.txt действительно сохранён в UTF-8, а переменная ключа не пуста:
if ([string]::IsNullOrWhiteSpace($env:OPENAI_API_KEY)) {
throw 'OPENAI_API_KEY не задан'
}
При ошибке HTTP PowerShell может выбросить исключение вместо обычного ответа. Сохраните текст ошибки и проверьте код, модель, права проекта и лимиты, не публикуя сам ключ.
Где искать перевод в JSON
У curl нет SDK-свойства output_text. Сырой ответ Responses API — это JSON-объект с полями вроде id, status и массива output; текст нужно извлечь из фактических элементов ответа. Поэтому после запроса полезно разобрать именно полученный JSON.
В Linux и macOS:
jq -r '
[.output[]?.content[]? | select(.type == "output_text") | .text]
| join("")
' response.json
Проверка с ненулевым кодом завершения, если текст не найден:
translation=$(jq -r '
[.output[]?.content[]? | select(.type == "output_text") | .text]
| join("")
' response.json)
if [ -z "$translation" ] || [ "$translation" = "null" ]; then
echo 'Перевод не найден в output' >&2
exit 1
fi
printf '%s\n' "$translation"
В PowerShell:
$json = Get-Content -Raw -Encoding utf8 .\response.json | ConvertFrom-Json
$translation = @(
foreach ($item in $json.output) {
foreach ($content in $item.content) {
if ($content.type -eq 'output_text') { $content.text }
}
}
) -join ''
if ([string]::IsNullOrWhiteSpace($translation)) {
throw 'Перевод не найден в output'
}
$translation
Если структура отличается, сначала посмотрите небольшой фрагмент response.json и сверяйте его с описанием Create a model response. Не подменяйте сырой ответ SDK-удобством: для командной строки важны реальные поля JSON.
Как проверить, что перевод полный
HTTP-код 2xx означает, что сервер принял запрос, но ещё не доказывает качество перевода. Проверьте как минимум четыре вещи:
- в ответе есть текст перевода, а не только
idили сообщение об ошибке; - сохранились числа, даты, имена и термины;
- не исчезли отрицания, условия и причинные связи;
- совпало количество смысловых фрагментов или абзацев, если разбиение было важно.
Для нашего примера вручную найдите в английской версии:
- срок
by Friday— «до пятницы»; - условие
If the deadline changes— «если срок изменится»; - просьбу сообщить заранее —
let me know in advance; - вежливые
Pleaseиplease, а не приказ без смягчения.
Фраза «пришлите договор до пятницы» и фраза «успеете прислать договор до пятницы?» могут вести к похожему действию, но это разные реплики: во второй есть место для ответа. В переводе нельзя незаметно заменить просьбу вопросом или убрать условие о переносе срока.
Если пропущен фрагмент, изменилось число или исчезло отрицание, не исправляйте смысл наугад. Сначала проверьте кодировку source.txt, затем уточните инструкцию: «Переведи весь текст без сокращений; сохрани порядок предложений и все числа». После повторного запроса снова сравните оригинал и результат вручную.
Если для оплаты нужен отдельный маршрут
Перевод через curl и пополнение OpenAI API — разные задачи. Amber Market может быть отдельным вариантом для читателя из России, которому нужно оплатить зарубежный цифровой сервис через посредника: посмотреть каталог услуг Amber Market. По рабочей карточке каталога заказ оплачивается через СБП, но это не означает пополнение OpenAI API или покупку API-баланса. Перед заказом проверьте актуальные условия карточки.
Итак, воспроизводимый маршрут состоит из простых проверяемых частей: UTF-8-файл, ключ в переменной окружения, POST /v1/responses, явные язык и контекст, разбор массива output и ручная сверка смысла. Модель помогает перевести текст, а полноту результата всё равно подтверждает человек.