asFrants's picture
add base security to api
cdd5b2f
raw history blame
No virus
5.95 kB
import os
import gradio as gr
import random
import secrets
from typing import Annotated
from fastapi import FastAPI, Request, status, Depends
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from fastapi.exceptions import HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from loguru import logger
from dotenv import load_dotenv
from app import Summarizer, TextRequest, Result
from app import (
EN_SENTIMENT_MODEL,
EN_SUMMARY_MODEL,
RU_SENTIMENT_MODEL,
RU_SUMMARY_MODEL,
)
from app import DEFAULT_EN_TEXT, DEFAULT_RU_TEXT
from models.forms import VerificationForm
load_dotenv()
SITE_KEY = os.getenv("SITE_KEY")
API_USER = os.getenv("API_USER")
API_PWD = os.getenv("API_PWD")
users = set()
app = FastAPI()
pipe = Summarizer()
security = HTTPBasic()
# mount FastAPI StaticFiles server
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
@app.get("/")
async def index(request: Request):
return RedirectResponse("/index/", status_code=302)
@app.get("/verify_page", response_class=HTMLResponse)
async def verify_page(request: Request):
captcha_id = random.randint(1, 5)
return templates.TemplateResponse(
request=request,
name="verification.html",
context={"site_key": SITE_KEY, "captcha_id": captcha_id},
)
@app.post("/verify")
async def verify(request: Request):
form = VerificationForm(request)
await form.load_data()
if await form.is_valid():
logger.info("Form is valid")
return RedirectResponse("/index/", status_code=302)
return await verify_page(request)
def get_current_username(
credentials: Annotated[HTTPBasicCredentials, Depends(security)]
):
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = bytes(API_USER, "utf-8")
is_correct_username = secrets.compare_digest(
current_username_bytes, correct_username_bytes
)
current_password_bytes = credentials.password.encode("utf8")
correct_password_bytes = bytes(API_PWD, "utf-8")
is_correct_password = secrets.compare_digest(
current_password_bytes, correct_password_bytes
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.post("/summ_ru", response_model=Result)
async def ru_summ_api(
request: TextRequest, username: Annotated[str, Depends(get_current_username)]
):
results = pipe.summarize(request.text, lang="ru")
logger.info(results)
return results
@app.post("/summ_en", response_model=Result)
async def en_summ_api(
request: TextRequest, username: Annotated[str, Depends(get_current_username)]
):
results = pipe.summarize(request.text, lang="en")
logger.info(results)
return results
@app.exception_handler(403)
async def unavailable_error(request: Request, exc: HTTPException):
logger.warning("Error 403")
return templates.TemplateResponse(
"errors/error.html",
{"request": request, "message": "403. Sorry, this page unavailable."},
status_code=403,
)
@app.exception_handler(404)
async def not_found_error(request: Request, exc: HTTPException):
logger.warning("Error 404")
return templates.TemplateResponse(
"errors/error.html",
{"request": request, "message": "404. Page Not Found."},
status_code=404,
)
@app.exception_handler(500)
async def internal_error(request: Request, exc: HTTPException):
logger.warning("Error 500")
return templates.TemplateResponse(
"errors/error.html",
{"request": request, "message": "500. Oops. Something has gone wrong."},
status_code=500,
)
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=2, min_width=600):
en_sum_description = gr.Markdown(
value=f"Model for Summary: {EN_SUMMARY_MODEL}"
)
en_sent_description = gr.Markdown(
value=f"Model for Sentiment: {EN_SENTIMENT_MODEL}"
)
en_inputs = gr.Textbox(
label="en_input",
lines=5,
value=DEFAULT_EN_TEXT,
placeholder=DEFAULT_EN_TEXT,
)
en_lang = gr.Textbox(value="en", visible=False)
en_outputs = gr.Textbox(
label="en_output",
lines=5,
placeholder="Summary and Sentiment would be here...",
)
en_inbtn = gr.Button("Proceed")
with gr.Column(scale=2, min_width=600):
ru_sum_description = gr.Markdown(
value=f"Model for Summary: {RU_SUMMARY_MODEL}"
)
ru_sent_description = gr.Markdown(
value=f"Model for Sentiment: {RU_SENTIMENT_MODEL}"
)
ru_inputs = gr.Textbox(
label="ru_input",
lines=5,
value=DEFAULT_RU_TEXT,
placeholder=DEFAULT_RU_TEXT,
)
ru_lang = gr.Textbox(value="ru", visible=False)
ru_outputs = gr.Textbox(
label="ru_output",
lines=5,
placeholder="Здесь будет обобщение и эмоциональный окрас текста...",
)
ru_inbtn = gr.Button("Запустить")
en_inbtn.click(
pipe.summ,
[en_inputs, en_lang],
[en_outputs],
)
ru_inbtn.click(
pipe.summ,
[ru_inputs, ru_lang],
[ru_outputs],
)
# mounting at the root path
app = gr.mount_gradio_app(app, demo, path="/index")