You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

130 lines
4.8 KiB

import os
import shutil
import uuid
from typing import Annotated
from fastapi import FastAPI, Request, UploadFile, Depends, Form, File, Cookie
from fastapi.templating import Jinja2Templates
from fastapi.security import OAuth2PasswordRequestForm
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from service import auth, reports
from service.db_requests import get_user
from service import structs
from service.models import User
app = FastAPI()
templates = Jinja2Templates(directory="client/templates")
app.mount("/static", StaticFiles(directory="client/static"), name="static")
app.add_middleware(
SessionMiddleware,
secret_key="CHANGEME",
session_cookie="session"
)
@app.get("/", response_class=RedirectResponse)
async def main_page(access_token: Annotated[str | None, Cookie()] = None):
if access_token:
try:
await auth.get_current_user(access_token)
except:
return RedirectResponse("/login")
return RedirectResponse("/upload-study")
else:
return RedirectResponse("/login")
@app.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
access_token = request.cookies.get("access_token")
if access_token:
try:
await auth.get_current_user(access_token)
return RedirectResponse("/upload-study", status_code=303)
except:
pass
response = templates.TemplateResponse("login.html", {"request": request})
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, private"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
@app.post("/login")
async def login_submit(request: Request,
login_data: OAuth2PasswordRequestForm = Depends()):
user = get_user(login_data.username)
if user is None or not auth.verify_password(login_data.password,
user.hashed_password):
return templates.TemplateResponse("login.html",
{"request": request, "error": True})
response = RedirectResponse("/upload-study", status_code=303)
response.set_cookie(
key = "access_token",
value = auth.create_access_token(user.username),
httponly=True
)
return response
@app.get("/upload-study", dependencies=[Depends(auth.get_current_user)])
async def upload_page(request: Request):
return templates.TemplateResponse("upload.html", {"request": request})
@app.post("/upload-study")
async def study_submit(
request: Request,
user: User = Depends(auth.get_current_user),
file: UploadFile = File(None),
demo_filename: str = Form(None),
pathology: str = Form(...)
):
user_dir = os.path.join("data", user.username)
os.makedirs(user_dir, exist_ok=True)
fpath = os.path.join(user_dir, str(uuid.uuid4()) + ".dcm")
if file and file.filename:
with open(fpath, 'wb') as buffer:
buffer.write(await file.read())
else:
demo_source_path = os.path.join("data/demo", pathology, demo_filename)
shutil.copy2(demo_source_path, fpath)
try:
prediction = reports.make_reports(pathology, fpath, user.username)
except (structs.TagError, structs.ImagesError) as e:
error_msg = e.msg + ". Загрузите другой файл."
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JSONResponse({"error": error_msg}, status_code=400)
else:
return templates.TemplateResponse("upload.html", {"request": request, "error": error_msg})
except Exception as e:
error_msg = "Ошибка анализа. Загрузите другой файл."
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JSONResponse({"error": error_msg}, status_code=500)
else:
return templates.TemplateResponse("upload.html", {"request": request, "error": error_msg})
request.session["prediction"] = prediction._asdict()
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JSONResponse({"redirect": "/ai-result"})
else:
return RedirectResponse("/ai-result", status_code=303)
@app.get("/ai-result", dependencies=[Depends(auth.get_current_user)])
async def result_page(request: Request):
prediction = request.session["prediction"]
return templates.TemplateResponse("result.html", {
"request": request,
"prediction": prediction
})
@app.get("/download/{filename}")
async def download_report(filename: str,
user: User = Depends(auth.get_current_user)):
return FileResponse(f"data/{user.username}/reports/{filename}")