Add multi-user auth, background generation, and chat UX improvements
Phase 5: Multi-user authentication with session cookies, bcrypt passwords, first-user-is-admin pattern, per-user data isolation, backup/restore, Docker Swarm production stack with secrets and network isolation. Phase 5.1: Chat UX improvements: - Background generation architecture (GenerationBuffer + asyncio task) with SSE fan-out, reconnect support, and periodic DB flushes - LLM-generated conversation titles (first exchange + every 10th message) - Stop generation button with cancel_event and partial content preservation - Relative timestamps in sidebar (5m ago, 3h ago, then dates) - Empty chat auto-cleanup on navigation away - Save-as-note uses LLM for title generation, tags notes with "chat" - Summarize-as-note also tags with "chat" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from quart import Quart, jsonify, make_response, request, send_from_directory
|
||||
from quart import Quart, g, jsonify, make_response, request, send_from_directory
|
||||
|
||||
from fabledassistant.config import Config
|
||||
from fabledassistant.routes.admin import admin_bp
|
||||
from fabledassistant.routes.api import api
|
||||
from fabledassistant.routes.auth import auth_bp
|
||||
from fabledassistant.routes.chat import chat_bp
|
||||
from fabledassistant.routes.notes import notes_bp
|
||||
from fabledassistant.routes.settings import settings_bp
|
||||
@@ -15,21 +18,49 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_app() -> Quart:
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||
level=getattr(logging, Config.LOG_LEVEL.upper(), logging.INFO),
|
||||
)
|
||||
|
||||
app = Quart(__name__, static_folder=None)
|
||||
app.secret_key = Config.SECRET_KEY
|
||||
|
||||
app.register_blueprint(admin_bp)
|
||||
app.register_blueprint(api)
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(chat_bp)
|
||||
app.register_blueprint(notes_bp)
|
||||
app.register_blueprint(settings_bp)
|
||||
app.register_blueprint(tasks_bp)
|
||||
|
||||
@app.before_request
|
||||
async def before_request():
|
||||
g.request_start = time.monotonic()
|
||||
|
||||
@app.after_request
|
||||
async def after_request(response):
|
||||
duration = time.monotonic() - getattr(g, "request_start", time.monotonic())
|
||||
duration_ms = round(duration * 1000, 1)
|
||||
logger.info(
|
||||
"%s %s %s %.1fms",
|
||||
request.method,
|
||||
request.path,
|
||||
response.status_code,
|
||||
duration_ms,
|
||||
)
|
||||
return response
|
||||
|
||||
@app.before_serving
|
||||
async def startup():
|
||||
import asyncio
|
||||
|
||||
from fabledassistant.services.generation_buffer import start_cleanup_loop
|
||||
from fabledassistant.services.llm import ensure_model
|
||||
|
||||
start_cleanup_loop()
|
||||
|
||||
async def _pull_model():
|
||||
try:
|
||||
await ensure_model(Config.OLLAMA_MODEL)
|
||||
@@ -70,11 +101,9 @@ def create_app() -> Quart:
|
||||
|
||||
@app.errorhandler(500)
|
||||
async def handle_500(error):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
logger.exception("Internal server error on %s %s", request.method, request.path)
|
||||
if request.path.startswith("/api/"):
|
||||
return jsonify({"error": str(error)}), 500
|
||||
return jsonify({"error": "Internal server error"}), 500
|
||||
return "Internal Server Error", 500
|
||||
|
||||
return app
|
||||
|
||||
Reference in New Issue
Block a user