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
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}") |