Столкнулся тут с проблемкой. Нужно было запустить 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 со всеми свойствами и методами.