Столкнулся тут с проблемкой. Нужно было запустить FastAPI через uvicorn. При этом обращения с сервера должны были идти на API OpenAI. Код писал на Python в VSCode. Запустить надо было по-быстрому. Нормальных VPN не нашел. «Спасибо» добрякам из Роскомнадзора…
В общем, как самый быстрый способ проверки работоспособностии работы OpenAI API с FastAPI получился такой:
- На ПК установлен Yandex Disk. На нем создана папка проекта.
- В VSCode проект на Python сохраняется на Yandex Disk.
- В Colab во первых строках кода исходники проекта скачиваются в локальную папку и добавляются в путь для поиска модулей.
- Как скачать и развернуть файлы проекта в Google Colab с Yandex Disk описано в другой статье.
- Подготавливается FastAPI.
- Поднимается ngrok.
- Запускается uvicorn.
Для подготовки FastAPI к запуску пример кода:
!pip install fastapi nest-asyncio pyngrok uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
# инициализация индексной базы
chunk = Chunk(path_to_base="Simble.txt")
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
# класс с типами данных параметров
class Item(BaseModel):
text: str
# функция обработки get запроса + декоратор
@app.get("/")
async def read_root():
return {"message": "answer"}
@app.get("/api/access_counter")
async def get_accesscouner():
counter = chunk.get_accesscouner()
return {"access_counter": counter}
# функция обработки post запроса + декоратор
@app.post("/api/get_answer")
async def get_answer(question: Item):
answer = chunk.get_answer(query=question.text)
return {"message": answer}Далее поднимаем ngrok. Передаем токен полученный при регистрации на Ngrok и предварительно сохраненый в .env. Подгружаем его через load_dotenv из папки загруженными с Yandex Disk исходниками:
dotenv_path = "/content/" + dirs[0] + "/.env" load_dotenv(dotenv_path)
и запускаем веб сервер uvicorn:
import nest_asyncio
from pyngrok import ngrok
import uvicorn
ngrok.set_auth_token(os.environ.get("NGROK_AUTHTOKEN"))
ngrok_tunnel = ngrok.connect(8000)
print('Public URL:', ngrok_tunnel.public_url)
nest_asyncio.apply()
uvicorn.run(app, port=8000)Сервер uvicorn повисает на временно сгенерированном ngrok внешнем домене.
Чтобы протестировать запуск сервера можно использовать запуск в командной строке curl:
curl -i -X POST -H "Content-Type: application/json" -d "{\"text\": \"Привет\"}" http://127.0.0.1:8000/api/get_answerДля бесплатных пользователей при создании аккаунта на Ngrok предоставляется один домен, который нужно создать в консоли ngrok (CloudEdge -> Domains). Выглядит он как-то так: «xxx.ngrok-free.app». Несколько доменов можно создать, купив платную подписку, но с проплатой из России проблемки. 🙂
Веб сервер Uvicorn туннелируется (пробрасывается) из Colab наружу через Ngrok и становится доступным для обращений по сгенерированному на Ngrok доменному имени. При обращениях по доменному имени запросы перенаправляются через Ngrok в Colab на Uvicorn и ответы возвращаются обратно.
ngrok_tunnel = ngrok.connect(8000, domain="your_domain.ngrok-free.app")
Возможно, есть достойные альтернативы ngrok, но времени на эксперименты не было.
Public URL: https://bb2f-34-16-145-243.ngrok-free.app INFO: Started server process [23974] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: 81.222.179.30:0 - "GET /api/access_counter HTTP/1.1" 200 OK INFO: 81.222.179.30:0 - "GET /api/access_counter HTTP/1.1" 200 OK INFO: Shutting down INFO: Waiting for application shutdown. INFO: Application shutdown complete. INFO: Finished server process [23974]
К сожалению, ячейка Colab запускается не асинхронно, т.е. управление с неё не передается на следующую ячейку. Гипотетически можно это обойти, запустив сервер через командную строку.
Для простоты я для тестирования использовал Postman. Вот так выглядит отправка запроса к серверу поднятому через ngrok на Colab.

Нюансы отправки REST API с помощью JavaScript через Ngrok
При отправке GET запросов на сервер через ngrok наверняка столкнетесь с тем, что стандартный JavaScript запрос выдает ошибку вида:
"Unexpected token '<', \"<!DOCTYPE \"... is not valid JSON" или Unexpected token '<', \"<!DOCTYPE ";... is not valid JSON"
При этом POST запрос у меня почему-то проходил без вопросов. Я сломал всю голову, не понимая, что происходит, поскольку в браузере и в Postman возвращался нормальный JSON и только при запуске обращения к сервере через JavaScript возникала эта ошибка. Затем наткнулся на этот сервер: https://reqbin.com/post-online для проверки GET запросов. Подсунув туда URL на ngrok я получил в response HTML страницу, вместо JSON.

Странно, что при отправке запросов через Postman и другие сервера они всегда возвращали правильный JSON. Чтобы bypass ngrok browser warning нужно добавить в header строку:
'ngrok-skip-browser-warning': 'any'
Добавление нестандартного User-Agent, как указано в рекомендациях, проблему решает в https://reqbin.com/post-online, но при вызове в JavaScript возникает та-же ошибка. Рабочий JavaScript код для обхода ошибки:
&lt;script>
const url = 'https://xxx.ngrok-free.app/api/counter';
//const url = "https://jsonplaceholder.typicode.com/posts/1";
var headers = new Headers(
{
'User-Agent': 'PostmanRuntime/7.36.0',
'Accept': 'application/json',
'ngrok-skip-browser-warning': 'any',
'Host': 'hugely-easy-pipefish.ngrok-free.app',
'Content-Type': 'application/json'
}
)
fetch(url, {
method: "GET",
headers: headers,
redirect: "follow"
}
).then(response => {
//console.log(response);
return response.json();
}
).then(data => {
console.log(data);
}
).catch(error => {
console.log(error.message);
}
)
&lt;/script>
Запускать скрипт для отладки удобно в https://jsfiddle.net/. Если раскомментарить строчку console.log(response), то в консоли jsfiddle отобразится объект response со всеми свойствами и методами.