Bypass Starlette Jinja2Templates - use Jinja2 directly with HTMLResponse

This commit is contained in:
Z User 2026-03-24 06:05:33 +00:00
parent d3c0dfbf5b
commit a2febd7dd9

View File

@ -9,7 +9,7 @@ from pathlib import Path
from typing import Optional, List from typing import Optional, List
from fastapi import APIRouter, Request, Response, Cookie, Form, UploadFile, File, HTTPException from fastapi import APIRouter, Request, Response, Cookie, Form, UploadFile, File, HTTPException
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
from fastapi.templating import Jinja2Templates from jinja2 import Environment, FileSystemLoader
from pydantic import BaseModel from pydantic import BaseModel
from loguru import logger from loguru import logger
@ -20,15 +20,18 @@ from core.orchestrator import Orchestrator
router = APIRouter() router = APIRouter()
# Templates - use string path for better compatibility # Templates - use Jinja2 directly without Starlette wrapper
# Disable cache to avoid hashing issues with Pydantic objects TEMPLATES_DIR = Path(__file__).parent / "templates"
from jinja2 import Environment, FileSystemLoader jinja_env = Environment(
template_env = Environment( loader=FileSystemLoader(str(TEMPLATES_DIR)),
loader=FileSystemLoader(str(Path(__file__).parent / "templates")),
autoescape=True, autoescape=True,
cache_size=0, # Disable cache
) )
templates = Jinja2Templates(env=template_env)
def render_template(name: str, context: dict) -> str:
"""Render a template with the given context."""
template = jinja_env.get_template(name)
return template.render(**context)
def get_template_settings(): def get_template_settings():
@ -90,28 +93,30 @@ async def landing_page(request: Request):
headers={"Location": "/chat"} headers={"Location": "/chat"}
) )
return templates.TemplateResponse( html = render_template("landing.html", {
"landing.html", "settings": get_template_settings()
{"request": request, "settings": get_template_settings()} })
) return HTMLResponse(content=html)
@router.get("/login", response_class=HTMLResponse) @router.get("/login", response_class=HTMLResponse)
async def login_page(request: Request, error: Optional[str] = None): async def login_page(request: Request, error: Optional[str] = None):
"""Login page.""" """Login page."""
return templates.TemplateResponse( html = render_template("login.html", {
"login.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": error} "error": error
) })
return HTMLResponse(content=html)
@router.get("/signup", response_class=HTMLResponse) @router.get("/signup", response_class=HTMLResponse)
async def signup_page(request: Request, error: Optional[str] = None): async def signup_page(request: Request, error: Optional[str] = None):
"""Signup page.""" """Signup page."""
return templates.TemplateResponse( html = render_template("signup.html", {
"signup.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": error} "error": error
) })
return HTMLResponse(content=html)
@router.post("/login") @router.post("/login")
@ -125,11 +130,11 @@ async def login_submit(
user = auth.authenticate(username, password) user = auth.authenticate(username, password)
if not user: if not user:
return templates.TemplateResponse( html = render_template("login.html", {
"login.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": "Invalid username or password"}, "error": "Invalid username or password"
status_code=401 })
) return HTMLResponse(content=html, status_code=401)
# Create session # Create session
token = auth.create_session(user.id) token = auth.create_session(user.id)
@ -157,28 +162,28 @@ async def signup_submit(
): ):
"""Process signup form.""" """Process signup form."""
if password != confirm_password: if password != confirm_password:
return templates.TemplateResponse( html = render_template("signup.html", {
"signup.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": "Passwords do not match"}, "error": "Passwords do not match"
status_code=400 })
) return HTMLResponse(content=html, status_code=400)
if len(password) < 6: if len(password) < 6:
return templates.TemplateResponse( html = render_template("signup.html", {
"signup.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": "Password must be at least 6 characters"}, "error": "Password must be at least 6 characters"
status_code=400 })
) return HTMLResponse(content=html, status_code=400)
auth = get_auth_manager() auth = get_auth_manager()
user = auth.create_user(username, email, password) user = auth.create_user(username, email, password)
if not user: if not user:
return templates.TemplateResponse( html = render_template("signup.html", {
"signup.html", "settings": get_template_settings(),
{"request": request, "settings": get_template_settings(), "error": "Username or email already exists"}, "error": "Username or email already exists"
status_code=400 })
) return HTMLResponse(content=html, status_code=400)
# Create session # Create session
token = auth.create_session(user.id) token = auth.create_session(user.id)
@ -225,15 +230,12 @@ async def chat_page(request: Request, session_token: Optional[str] = Cookie(None
rate_info = auth.check_rate_limit(user.id) rate_info = auth.check_rate_limit(user.id)
return templates.TemplateResponse( html = render_template("chat.html", {
"chat.html", "settings": get_template_settings(),
{ "user": user,
"request": request, "rate_info": rate_info
"settings": get_template_settings(), })
"user": user, return HTMLResponse(content=html)
"rate_info": rate_info
}
)
@router.get("/profile", response_class=HTMLResponse) @router.get("/profile", response_class=HTMLResponse)
@ -254,16 +256,13 @@ async def profile_page(request: Request, session_token: Optional[str] = Cookie(N
documents = auth.get_user_documents(user.id) documents = auth.get_user_documents(user.id)
rate_info = auth.check_rate_limit(user.id) rate_info = auth.check_rate_limit(user.id)
return templates.TemplateResponse( html = render_template("profile.html", {
"profile.html", "settings": get_template_settings(),
{ "user": user,
"request": request, "documents": documents,
"settings": get_template_settings(), "rate_info": rate_info
"user": user, })
"documents": documents, return HTMLResponse(content=html)
"rate_info": rate_info
}
)
# ============================================================================ # ============================================================================