Всем привет! Сегодня я расскажу вам, как я сделал сервис для обхода блокировки OpenAI в россии со стороны OpenAI (не Роскомнадзор даже) с использованием FastAPI и Docker. Мотивация проста. У меня в РФ есть сервер на котором работают сервисы и я хочу подключить к ним OpenAI, но они не дают доступ, распознавая IP из россии. Подумал что напишу сервер для пересылки запроса. Если вам интересно, как за несколько шагов запаковать работу с ИИ в красивую и простую оболочку, то устраивайтесь поудобнее. Мы вместе погрузимся в этот увлекательный процесс!
О чем вообще речь?
Сперва подумал что лучше сделать реле HTTP запросов, но оказалось что там все куда сложнее и OpenAI использует систему Cookie подложенную в запросы и сервер в другом часовом поясе не будет работать, поэтому я поменял стратегию:
Идея проста: я хотел создать веб-сервис, который может принимать сообщения и с помощью API OpenAI выдавать осмысленные и даже забавные ответы. Однако вместо того, чтобы напрямую обращаться к OpenAI API через скрипты, я решил сделать что-то более изящное — API для API! И для этого выбрал FastAPI, который обещает высокую производительность, простоту в использовании и асинхронность из коробки.
А чтобы всё это легко запускалось где угодно (будь то локально или на сервере), я завернул проект в Docker. Почему бы и нет? Ведь с Docker работать приятно — раз поднял контейнер, и можно забыть о всяких проблемах с окружением.
Ну что, начнем!
Ответы на популярные вопросы:
Почему не VPN?
Не хочу чтобы весь трафик ходил через VPN а выборочно гемор настраивать!
Почему не NGINX?
Не решил проблему с подменой SSL сертификатов, а без нее не будет работать официальный питоновский клиент все равно.
Конфиг который пробовал:
# nginx.conf
server {
listen 80;
server_name your_relay_server_domain;
# Reverse proxy to OpenAI API
location / {
proxy_pass https://api.openai.com; # Forward all requests to the OpenAI API
# Set proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Optionally add timeouts or other restrictions
proxy_read_timeout 90;
}
}
FastAPI: как можно не любить этот фреймворк?
Если вы до сих пор не слышали про FastAPI, то срочно идите читать! Этот фреймворк — настоящая находка для тех, кто устал от громоздкости старых фреймворков и хочет чего-то простого, но мощного.
Моя цель была проста: сделать POST-запрос, который принимает список сообщений (например, фразы от пользователя и инструкции от системы) и возвращает ответ, сгенерированный моделью OpenAI (будь то GPT-4 или GPT-3.5). Ну и, конечно, я хотел добавить аутентификацию — ведь не хотелось, чтобы кто угодно мог получить доступ к сервису.
Код сервиса — это несколько строк, которые показывают всю мощь FastAPI:
from fastapi import FastAPI, HTTPException, Request, Depends
from pydantic import BaseModel
import openai
import os
from dotenv import load_dotenv
# Загружаем переменные окружения из .env файла
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
AUTH_TOKEN = os.getenv("AUTH_TOKEN")
app = FastAPI()
class OpenAIRequest(BaseModel):
model_name: str
messages: list[dict[str, str]]
def verify_token(request: Request):
token = request.headers.get("Authorization")
if token != AUTH_TOKEN:
raise HTTPException(status_code=403, detail="Unauthorized")
@app.post("/api/open_ai_request")
async def open_ai_request(openai_request: OpenAIRequest, token: None = Depends(verify_token)):
openai.api_key = OPENAI_API_KEY
response = openai.ChatCompletion.create(
model=openai_request.model_name,
messages=openai_request.messages
)
return {"response": response.choices[0].message['content']}
Что здесь происходит?
FastAPI предоставляет удобный интерфейс для создания HTTP-методов.
Мы используем асинхронные функции для максимальной производительности.
Добавили базовую проверку токена через заголовок
Authorization
, чтобы никто не мог использовать ваш сервис без разрешения.Самое главное — запросы к OpenAI выполняются с помощью асинхронного вызова API, чтобы всё летало как нужно!
Docker: чтобы не было «на моем компьютере работает»
Теперь давайте завернем наш сервис в Docker. Это позволит запускать его в любом окружении без мучений с установкой зависимостей.
Dockerfile у нас очень простой:
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Что здесь происходит?
Мы берем легковесный образ Python 3.10.
Устанавливаем все необходимые зависимости (FastAPI, OpenAI и прочее).
Копируем исходники приложения.
И запускаем сервис через Uvicorn, который является отличным сервером для асинхронных приложений.
Но это еще не всё! Для удобства мы добавим docker-compose, чтобы всё поднималось одной командой:
version: '3.8'
services:
fastapi-openai-service:
build: .
env_file:
- .env
ports:
- "8000:8000"
restart: unless-stopped
Теперь, чтобы запустить сервис, достаточно просто:
docker-compose up --build
И через несколько секунд у вас готовый сервис для общения с ИИ, который работает на любом сервере или даже локально.
Проверим работу
После того как вы запустили контейнер, ваш сервис будет доступен по адресу http://localhost:8000
. Вы можете отправить POST-запрос с заголовком авторизации и телом запроса, например, с помощью curl
:
curl -X POST "http://localhost:8000/api/open_ai_request" \
-H "Authorization: your_secret_auth_token_here" \
-H "Content-Type: application/json" \
-d '{
"model_name": "gpt-4",
"messages": [
{"role": "system", "content": "Ты умный ассистент."},
{"role": "user", "content": "Расскажи шутку."}
]
}'
И вы получите в ответ что-то вроде:
{ "response": "Почему программисты не любят ходить в лес? Потому что там слишком много багов!"
}
Неплохо, да?
Что можно улучшить?
Как и любой проект, этот сервис можно доработать и расширить, чтобы повысить его функциональность и надежность. Вот несколько идей для улучшений:
Проверка токена не простым сравнением, а сравнением хешей. Хеша токена или сравнение с постоянной скоростью.
На данный момент у нас простая проверка токена через заголовок
Authorization
. Можно улучшить безопасность, добавив систему авторизации на основе JWT или OAuth 2.0, а также разграничить права доступа для разных типов пользователей.Важно добавить автоматизированные тесты, чтобы убедиться в стабильности работы сервиса при его доработке. Можно использовать
pytest
для написания юнит-тестов, а также инструменты для нагрузочного тестирования, такие какLocust
илиk6
, чтобы проверить производительность.
Подводим итоги
Мы создали простой, но функциональный сервис, который можно развернуть на вашей VPS после чего он будет отправлять запросы к OpenAI и возвращать ответы. При этом весь проект легко масштабируем и готов к деплою благодаря Docker и FastAPI.
Чем хорош этот подход:
Легкость развертывания: Docker помогает избегать проблем с зависимостями и окружениями.
Масштабируемость: FastAPI — быстрый и асинхронный фреймворк, что позволяет обрабатывать множество запросов без потери производительности.
Безопасность: Простая проверка токена позволяет ограничить доступ к вашему сервису.
Теперь вы знаете, как можно сделать API для работы с OpenAI буквально за пару часов. Вперед к новым свершениям, и пусть ИИ помогает вам во всех ваших начинаниях!
Жду ваших комментариев и предложений по улучшению!
Комментарии (25)
janvarev
15.10.2024 04:58Ох. Я поддерживаю сервис, который как раз предоставляет прокси OpenAI API для нейросетей в России и релеит запросы оригинальным сервисам (в профиле есть).
Что могу сказать - по факту, вы закрыли ровно 1 кейс - т.е. отправка чисто сообщений. Не учитывается - передача температуры, параметра tools (т.е. схемы инструментов для формальных запросов) и ряда других. Не поддерживается стриминг - это такая хитрая штука, когда при ответе отсылается последовательно ряд HTTP-events, которая рендерится на клиенте (нужно, чтобы не ждать ответа от сети полностью, т.к. может быть долго, можно выводить по кусочкам). Еще понятное дело, у вас только под текстовый запрос - т.е. не поддерживаются DALL-E, embeddings, TTS, STT... :)
vanyas
15.10.2024 04:58А не проще было просто nginx с proxy_pass поднять?
mikprin Автор
15.10.2024 04:58Я не пробовал nginx прокси, можно попробовать, но кажется он палит cookies. И разницу в часовых поясах прокси и сервера. Но я попробую
mikprin Автор
15.10.2024 04:58Если дадите нормальную конфигурацию для nginx это была бы польза. Я попрбовал:
# nginx.conf server { listen 80; server_name your_relay_server_domain; # Reverse proxy to OpenAI API location / { proxy_pass https://api.openai.com; # Forward all requests to the OpenAI API # Set proxy headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Optionally add timeouts or other restrictions proxy_read_timeout 90; } }
но она дает конфликт SSL:
2024/10/16 12:43:36 [error] 27#27: *1 SSL_do_handshake() failed (SSL: error:0A000410:SSL routines::sslv3 alert handshake failure:SSL alert number 40) while SSL handshaking to upstream, client: ***, server: your_relay_server_domain, request: "POST /v1/chat/completions HTTP/1.1", upstream: "https://***:443/v1/chat/completions", host: "***" 2024/10/16 12:43:36 [warn] 27#27: *1 upstream server temporarily disabled while SSL handshaking to upstream, client: ***, server: your_relay_server_domain, request: "POST /v1/chat/completions HTTP/1.1", upstream: "https://***:443/v1/chat/completions", host: "***" 2024/10/16 12:43:36 [error] 27#27: *1 SSL_do_handshake() failed (SSL: error:0A000410:SSL routines::sslv3 alert handshake failure:SSL alert number 40) while SSL handshaking to upstream, client: ***, server: your_relay_server_domain, request: "POST /v1/chat/completions HTTP/1.1", upstream: "https://***:443/v1/chat/completions", host: "***"
Devastor87
15.10.2024 04:58У меня в РФ есть сервер на котором работают сервисы и я хочу подключить к ним OpenAI, но они не дают доступ, распознавая IP из россии. Подумал что напишу сервер для пересылки запроса.
И
Мы создали простой, но функциональный сервис, который можно развернуть на вашей VPS после чего он будет отправлять запросы к OpenAI и возвращать ответы.
Не совсем понял: так в итоге получилось отправлять запросы с российского сервиса (минуя блокировки по IP), или VDS нужен забугорный?
d-sh
15.10.2024 04:58Может чел просто ни разу в жизни не слышал о прокси.
mikprin Автор
15.10.2024 04:58Я не пробовал nginx прокси, можно попробовать, но кажется он палит cookies. Те что я попробовал не работали в разных часовых поясах. И разницу в часовых поясах прокси и сервера.
p.s. попробовал NGINX. там есть проблемы с SSL которые если вы знаете как решить меньше чем за час милости прошу рассказать. Использовал такой конфиг:# nginx.conf server { listen 80; server_name your_relay_server_domain; # Reverse proxy to OpenAI API location / { proxy_pass https://api.openai.com; # Forward all requests to the OpenAI API # Set proxy headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Optionally add timeouts or other restrictions proxy_read_timeout 90; } }
Меня послал SSL по понятным причинам.
Digitalnomad
15.10.2024 04:58А не проще сервак купить у timeweb ничего не делая подобного? Уже больше года полет нормальный.
mikprin Автор
15.10.2024 04:58Нет, у меня есть сервер который я хочу использовать. Но да можно конечно арендовать машину.
c0r3dump
15.10.2024 04:58Не хочу чтобы весь трафик ходил через VPN а выборочно гемор настраивать!
Что сложного отправить через vpn только то, что идёт на OpenAI, их сети же поди все известны?
Ingener74
Не проще VPN поднять?
Пользуюсь ChatGPT через свой VPN. На своей хоумлабе держу тг бота который ходит в OpenAI API через этот же VPN и всё хорошо.
Pitcentr0
есть где подробнее прочитать что бы отправлять ТГ бота через VPN ?
Ingener74
Я использую вот этот docker image https://github.com/dperson/openvpn-client?tab=readme-ov-file#local-network-access-to-services-connecting-to-the-internet-through-the-vpn чтобы некоторые мои контейнеры выходили в инет через VPN
mikprin Автор
Вот это полезнее уже чем просто вопрос про VPN!
mikprin Автор
Когда у тебя дело про сервер нет.
Ingener74
Какое дело? Про какой сервер?
mikprin Автор
Сам код который использует OPEN AI у меня крутится на сервере весь трафик с которого не хочу через VPN гнать. Даже весь трафик контейнера гнать через VPN излишне!
Ingener74
Всё равно как то странно выглядит, проще кажется сделать рядом контейнер с прокси который будет в openai ходить через VPN и а остальной трафик пускать без VPN.
Crash13
Статья о первом своем api :) , а не "как заплатить денег и не напрягаться" :)
IMHO, Если рассуждать, следуя Вашему тезису, то можно просто "три копейки закинуть" сервисам-посредникам и не напрягаясь пользоваться без всяких "подъемов своих vpn". )