Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
from collections.abc import AsyncIterator, Awaitable, Callable
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, Request, Response
|
||||
|
||||
from app.api import api_router
|
||||
from app.db import async_session_factory
|
||||
from app.errors import register_exception_handlers
|
||||
from app.help_import import import_help_documents
|
||||
from app.ingestion.handlers import ensure_retention_scheduled
|
||||
from app.ingestion.queue import run_queue
|
||||
from app.llm.overrides import bootstrap_llm_settings
|
||||
from app.llm.overrides import load_config as load_llm_config
|
||||
from app.log import correlation_id, setup_logging
|
||||
from app.prompts.overrides import load_config as load_prompt_config
|
||||
from app.template_catalog import seed_starter_templates
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
setup_logging()
|
||||
async with async_session_factory() as db:
|
||||
await ensure_retention_scheduled(db)
|
||||
await seed_starter_templates(db)
|
||||
await import_help_documents(db)
|
||||
await bootstrap_llm_settings(db)
|
||||
await load_llm_config(db)
|
||||
await load_prompt_config(db)
|
||||
stop_event = asyncio.Event()
|
||||
queue_task = asyncio.create_task(run_queue(stop_event))
|
||||
yield
|
||||
stop_event.set()
|
||||
try:
|
||||
await asyncio.wait_for(queue_task, timeout=10)
|
||||
except TimeoutError: # pragma: no cover — a handler refused to finish
|
||||
queue_task.cancel()
|
||||
|
||||
|
||||
app = FastAPI(title="Pablan", version="0.1.0", lifespan=lifespan)
|
||||
register_exception_handlers(app)
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def add_correlation_id(
|
||||
request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
||||
) -> Response:
|
||||
cid = request.headers.get("x-request-id") or uuid.uuid4().hex[:16]
|
||||
token = correlation_id.set(cid)
|
||||
try:
|
||||
response = await call_next(request)
|
||||
finally:
|
||||
correlation_id.reset(token)
|
||||
response.headers["x-request-id"] = cid
|
||||
return response
|
||||
|
||||
|
||||
app.include_router(api_router)
|
||||
Reference in New Issue
Block a user